Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: e36614cb2a60792949fd6d3581affbc472f5c0dd (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                                





                                                                        
                                                     
                                                                                 



                                                      
                                             
                                             
                                                                   

   
                                                                                       




                                                       
                                                                                            









                                         

                                           
 



                                                                                                        
                                                        
         
 

                                                                          
                                                         
         




                                                                                                   
 



                                                                     


















                                                                       
 








                                                                                                                                        
 

















                                                                                                                                         



                                                                                        
                                     
                 

                             


                                                           
                                                                                    
                                     
 






                                                                                                    


           
                                                                     







                                                                                  



                                                                                          
                                     

                                                                                  
                 

                             














                                                                     
                                                                                                 





                                                                              
 


                                                   
                                                         







                                                                 
                                                                                                

                                     

                                        



                                                                         
                                                                                 














                                                                  

                                                                                                       
                                                                                                                                           
                                                                                                
                                   
 









                                                                                         


                                                                                                        
                                                                                                                                                                                 
                                                                                                
                                   
 









                                                                                         
         
 
/*******************************************************************************
 * Copyright (c) 2008, 2010 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
 *******************************************************************************/
package org.eclipse.cdt.internal.core.dom.parser;

import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTImageLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IASTNode;
import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion;

/**
 * For searching ast-nodes by offset and length, instances of this class can be used to
 * determine whether a node matches or not.
 *
 * @since 5.0
 */
public class ASTNodeSpecification<T extends IASTNode> {
	public enum Relation { FIRST_CONTAINED, EXACT_MATCH, ENCLOSING, STRICTLY_ENCLOSING }

	private final Class<T> fClass;
	private final Relation fRelation;
	private final int fFileOffset;
	private final int fFileEndOffset;
	private int fSeqNumber;
	private int fSeqEndNumber;
	private int fBestOffset;
	private int fBestEndOffset;
	private T fBestNode;
	private boolean fSearchInExpansion;
	private boolean fZeroToLeft= false;

	public ASTNodeSpecification(Relation relation, Class<T> clazz, int fileOffset, int fileLength) {
		fRelation= relation;
		fClass= clazz;
		fFileOffset= fileOffset;
		fFileEndOffset= fileOffset + fileLength;
	}

	public void setRangeInSequence(int offsetInSeq, int lengthInSeq) {
		fSeqNumber= offsetInSeq;
		fSeqEndNumber= offsetInSeq + lengthInSeq;
	}

	public void setRangeInSequence(int offsetInSeq, int lengthInSeq, boolean zeroRangeToLeft) {
		setRangeInSequence(offsetInSeq, lengthInSeq);
		fZeroToLeft= zeroRangeToLeft;
	}

	public void setSearchInExpansion(boolean searchInExpansion) {
		fSearchInExpansion= searchInExpansion;
	}

	public Relation getRelationToSelection() {
		return fRelation;
	}

	public int getSequenceStart() {
		return fSeqNumber;
	}

	public int getSequenceEnd() {
		return fSeqEndNumber;
	}

	public T getBestNode() {
		return fBestNode;
	}

	public boolean requiresClass(Class<? extends IASTNode> clazz) {
		return clazz.isAssignableFrom(fClass);
	}

	@SuppressWarnings("unchecked")
	public void visit(ASTNode astNode) {
		if (isAcceptableNode(astNode) && isMatchingRange(astNode.getOffset(), astNode.getLength(), fSeqNumber, fSeqEndNumber)) {
			IASTFileLocation loc= astNode.getFileLocation();
			if (loc != null) {
				storeIfBest(loc, (T) astNode);
			}
		}
	}

	@SuppressWarnings("unchecked")
	public void visit(ASTNode astNode, IASTImageLocation imageLocation) {
		if (isAcceptableNode(astNode) && imageLocation != null) {
			if (isMatchingRange(imageLocation.getNodeOffset(), imageLocation.getNodeLength(), fFileOffset, fFileEndOffset)) {
				storeIfBest(imageLocation, (T) astNode);
			}
		}
	}

	private boolean isMatchingRange(int offset, int length, int selOffset, int selEndOffset) {
		final int endOffset= offset+length;
		switch(fRelation) {
		case EXACT_MATCH:
			return selOffset == offset && selEndOffset == endOffset;
		case FIRST_CONTAINED:
			return selOffset <= offset && endOffset <= selEndOffset;
		case ENCLOSING:
			return offset <= selOffset && selEndOffset <= endOffset;
		case STRICTLY_ENCLOSING:
			if (offset <= selOffset && selEndOffset <= endOffset) {
				return offset != selOffset || selEndOffset != endOffset;
			}
			return false;
		}
		assert false;
		return false;
	}

	public boolean isAcceptableNode(IASTNode astNode) {
		if (astNode == null || !fClass.isAssignableFrom(astNode.getClass()))
			return false;

		if (fSearchInExpansion) {
			IASTNode check= astNode instanceof IASTName ? astNode.getParent() : astNode;
			if (check instanceof IASTPreprocessorMacroExpansion) {
				return false;
			}
		}
		return true;
	}

	/**
	 * Returns whether the node can contain matches in its range.
	 */
	public boolean canContainMatches(ASTNode node) {
		final int offset= node.getOffset();
		final int endOffset= offset+node.getLength();
		switch(fRelation) {
		case EXACT_MATCH:
		case ENCLOSING:
			return offset <= fSeqNumber && fSeqEndNumber <= endOffset;
		case STRICTLY_ENCLOSING:
			if (offset <= fSeqNumber && fSeqEndNumber <= endOffset) {
				return offset != fSeqNumber || fSeqEndNumber != endOffset;
			}
			return false;
		case FIRST_CONTAINED:
			return offset <= fSeqEndNumber && fSeqNumber <= endOffset;
		}
		assert false;
		return false;
	}

	private void storeIfBest(IASTFileLocation loc, T astNode) {
		if (loc != null) {
			final int offset = loc.getNodeOffset();
			final int length = loc.getNodeLength();
			if (isBetterMatch(offset, length, astNode)) {
				fBestNode= astNode;
				fBestOffset= offset;
				fBestEndOffset= offset+length;
			}
		}
	}

	/**
	 * Assuming that the given range matches, this method returns whether the match is better
	 * than the best match stored.
	 */
	private boolean isBetterMatch(int offset, int length, IASTNode cand) {
		if (fBestNode == null) {
			return true;
		}

		final int endOffset= offset+length;
		switch(fRelation) {
		case EXACT_MATCH:
			return isParent(fBestNode, cand);
		case FIRST_CONTAINED:
			if (offset < fBestOffset) {
				return true;
			}
			if (offset == fBestOffset) {
				if (endOffset < fBestEndOffset) {
					return true;
				}
				return endOffset == fBestEndOffset && isParent(fBestNode, cand);
			}
			return false;
		case ENCLOSING:
		case STRICTLY_ENCLOSING:
			final int bestLength= fBestEndOffset-fBestOffset;
			if (length < bestLength) {
				return true;
			}
			return length == bestLength && isParent(fBestNode, cand);
		default:
			assert false;
			return false;
		}
	}

	private boolean isParent(IASTNode cand1, IASTNode cand2) {
		while(cand2 != null) {
			if (cand2 == cand1) {
				return true;
			}
			cand2= cand2.getParent();
		}
		return false;
	}

	public IASTPreprocessorMacroExpansion findLeadingMacroExpansion(ASTNodeSelector nodeSelector) {
		IASTPreprocessorMacroExpansion exp= nodeSelector.findEnclosingMacroExpansion(fZeroToLeft ? fFileOffset-1 : fFileOffset, 1);
		if (fRelation == Relation.ENCLOSING || fRelation == Relation.STRICTLY_ENCLOSING)
			return exp;

		if (exp != null) {
			IASTFileLocation loc= exp.getFileLocation();
			if (loc != null) {
				final int offset= loc.getNodeOffset();
				final int endOffset= offset+loc.getNodeLength();
				if (offset == fFileOffset && endOffset <= fFileEndOffset)
					return exp;
			}
		}
		return null;
	}

	public IASTPreprocessorMacroExpansion findTrailingMacroExpansion(ASTNodeSelector nodeSelector) {
		IASTPreprocessorMacroExpansion exp= nodeSelector.findEnclosingMacroExpansion(fFileEndOffset==fFileOffset && !fZeroToLeft ? fFileEndOffset : fFileEndOffset-1, 1);
		if (fRelation == Relation.ENCLOSING || fRelation == Relation.STRICTLY_ENCLOSING)
			return exp;

		if (exp != null) {
			IASTFileLocation loc= exp.getFileLocation();
			if (loc != null) {
				final int offset= loc.getNodeOffset();
				final int endOffset= offset+loc.getNodeLength();
				if (endOffset == fFileEndOffset && offset >= fFileOffset)
					return exp;
			}
		}
		return null;
	}
}

Back to the top