diff options
Diffstat (limited to 'core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser')
4 files changed, 297 insertions, 53 deletions
diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeMatchKind.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeMatchKind.java new file mode 100644 index 00000000000..ff4a186f9d3 --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeMatchKind.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 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: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser; + +import org.eclipse.cdt.core.dom.ast.IASTName; + +/** + * 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 ASTNodeMatchKind { + public enum Relation {FIRST_CONTAINED, EXACT, SURROUNDING} + + static final ASTNodeMatchKind MATCH_EXACT= new ASTNodeMatchKind(Relation.EXACT, false); + static final ASTNodeMatchKind MATCH_EXACT_NAME= new ASTNodeMatchKind(Relation.EXACT, true); + static final ASTNodeMatchKind MATCH_FIRST_CONTAINED= new ASTNodeMatchKind(Relation.FIRST_CONTAINED, false); + static final ASTNodeMatchKind MATCH_FIRST_NAME_CONTAINED= new ASTNodeMatchKind(Relation.FIRST_CONTAINED, true); + static final ASTNodeMatchKind MATCH_SURROUNDING= new ASTNodeMatchKind(Relation.SURROUNDING, false); + static final ASTNodeMatchKind MATCH_SURROUNDING_NAME= new ASTNodeMatchKind(Relation.SURROUNDING, true); + + private boolean fNamesOnly; + private Relation fRelation; + + private ASTNodeMatchKind(Relation relation, boolean namesOnly) { + fRelation= relation; + fNamesOnly= namesOnly; + } + + public Relation getRelationToSelection() { + return fRelation; + } + + public boolean matchNamesOnly() { + return fNamesOnly; + } + + /** + * Returns whether the node matches the selection. + */ + public boolean matches(ASTNode node, int selOffset, int selLength) { + if (fNamesOnly && node instanceof IASTName == false) { + return false; + } + + final int nodeOffset= node.getOffset(); + final int nodeLength= node.getLength(); + switch(fRelation) { + case EXACT: + return selOffset == nodeOffset && selLength == nodeLength; + case FIRST_CONTAINED: + return selOffset <= nodeOffset && nodeOffset+nodeLength <= selOffset+selLength; + case SURROUNDING: + return nodeOffset <= selOffset && selOffset+selLength <= nodeOffset+nodeLength; + default: + assert false; + return false; + } + } + + /** + * Returns whether the node is a lower bound for matching the selection. A node is a lower + * bound when a node to the left of the given one cannot match the selection. + */ + public boolean isLowerBound(ASTNode node, int selOffset, int selLength) { + final int nodeOffset= node.getOffset(); + switch(fRelation) { + case SURROUNDING: + case EXACT: + return nodeOffset < selOffset+selLength; + case FIRST_CONTAINED: + return nodeOffset <= selOffset; + default: + assert false; + return false; + } + } + + /** + * Returns whether cand1 is a better match than cand2, prefers cand1 in case of doubt. + */ + public boolean isBetterMatch(ASTNode cand1, ASTNode cand2) { + if (cand1 == null) + return false; + if (cand2 == null) + return true; + + final int nodeOffset1= cand1.getOffset(); + final int nodeLength1= cand1.getLength(); + final int nodeOffset2= cand2.getOffset(); + final int nodeLength2= cand2.getLength(); + switch(fRelation) { + case EXACT: + return true; + case FIRST_CONTAINED: + return nodeOffset1 < nodeOffset2 || (nodeOffset1 == nodeOffset2 && nodeLength1 <= nodeLength2); + case SURROUNDING: + return nodeLength1 <= nodeLength2; + default: + assert false; + return false; + } + } +}
\ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java new file mode 100644 index 00000000000..75b1fbe130f --- /dev/null +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTNodeSelector.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 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: + * Markus Schorn - initial API and implementation + *******************************************************************************/ +package org.eclipse.cdt.internal.core.dom.parser; + +import org.eclipse.cdt.core.dom.ast.IASTMacroExpansionLocation; +import org.eclipse.cdt.core.dom.ast.IASTName; +import org.eclipse.cdt.core.dom.ast.IASTNode; +import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; +import org.eclipse.cdt.internal.core.dom.parser.ASTNodeMatchKind.Relation; +import org.eclipse.cdt.internal.core.parser.scanner.ILocationResolver; + +/** + * Class to support searching for nodes by offsets. + * @since 5.0 + */ +public class ASTNodeSelector implements IASTNodeSelector { + + private ASTTranslationUnit fTu; + private ILocationResolver fLocationResolver; + private String fFilePath; + private final boolean fIsValid; + + public ASTNodeSelector(ASTTranslationUnit tu, ILocationResolver locationResolver, String filePath) { + fTu= tu; + fLocationResolver= locationResolver; + fFilePath= filePath; + fIsValid= verify(); + } + + private boolean verify() { + if (fLocationResolver != null) { + if (fFilePath == null) { + fFilePath= fLocationResolver.getTranslationUnitPath(); + } + return true; + } + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getNode(int, int) + */ + private IASTNode getNode(int offset, int length, ASTNodeMatchKind matchKind) { + if (!fIsValid) { + return null; + } + + final int sequenceNumber= fLocationResolver.getSequenceNumberForFileOffset(fFilePath, offset); + if (sequenceNumber < 0) { + return null; + } + final int sequenceLength= length <= 0 ? 0 : + fLocationResolver.getSequenceNumberForFileOffset(fFilePath, offset+length-1) + 1 - sequenceNumber; + + ASTNode preCand= searchPreprocessor(sequenceNumber, sequenceLength, matchKind); + if (preCand != null && matchKind.getRelationToSelection() != Relation.FIRST_CONTAINED) { + return preCand; + } + ASTNode astCand= searchAST(sequenceNumber, sequenceLength, matchKind); + return matchKind.isBetterMatch(preCand, astCand) ? preCand : astCand; + } + + private ASTNode searchPreprocessor(int sequenceNumber, int sequenceLength, ASTNodeMatchKind matchKind) { + return fLocationResolver.findPreprocessorNode(sequenceNumber, sequenceLength, matchKind); + } + + private ASTNode searchAST(int sequenceNumber, int length, ASTNodeMatchKind matchKind) { + FindNodeForOffsetAction nodeFinder= new FindNodeForOffsetAction(sequenceNumber, length, matchKind); + fTu.accept(nodeFinder); + ASTNode result= nodeFinder.getNode(); + // don't accept matches from the ast enclosed in a macro expansion (possible for contained matches, only) + if (result != null && + matchKind.getRelationToSelection() == Relation.FIRST_CONTAINED) { + IASTNodeLocation[] loc= result.getNodeLocations(); + if (loc.length > 0 && loc[0] instanceof IASTMacroExpansionLocation) { + return null; + } + } + return result; + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getFirstContainedNode(int, int) + */ + public IASTNode findFirstContainedNode(int offset, int length) { + return getNode(offset, length, ASTNodeMatchKind.MATCH_FIRST_CONTAINED); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getNode(int, int) + */ + public IASTNode findNode(int offset, int length) { + return getNode(offset, length, ASTNodeMatchKind.MATCH_EXACT); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getSurroundingNode(int, int) + */ + public IASTNode findSurroundingNode(int offset, int length) { + return getNode(offset, length, ASTNodeMatchKind.MATCH_SURROUNDING); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getFirstContainedNode(int, int) + */ + public IASTName findFirstContainedName(int offset, int length) { + return (IASTName) getNode(offset, length, ASTNodeMatchKind.MATCH_FIRST_NAME_CONTAINED); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getNode(int, int) + */ + public IASTName findName(int offset, int length) { + return (IASTName) getNode(offset, length, ASTNodeMatchKind.MATCH_EXACT_NAME); + } + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTNodeSelector#getSurroundingNode(int, int) + */ + public IASTName findSurroundingName(int offset, int length) { + return (IASTName) getNode(offset, length, ASTNodeMatchKind.MATCH_SURROUNDING_NAME); + } + +}
\ No newline at end of file diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java index caa28508919..4cdf3a28a88 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/ASTTranslationUnit.java @@ -21,8 +21,10 @@ import org.eclipse.cdt.core.dom.ast.IASTFileLocation; import org.eclipse.cdt.core.dom.ast.IASTName; import org.eclipse.cdt.core.dom.ast.IASTNode; import org.eclipse.cdt.core.dom.ast.IASTNodeLocation; +import org.eclipse.cdt.core.dom.ast.IASTNodeSelector; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorIncludeStatement; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroDefinition; +import org.eclipse.cdt.core.dom.ast.IASTPreprocessorMacroExpansion; import org.eclipse.cdt.core.dom.ast.IASTPreprocessorStatement; import org.eclipse.cdt.core.dom.ast.IASTProblem; import org.eclipse.cdt.core.dom.ast.IASTTranslationUnit; @@ -139,11 +141,20 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat return EMPTY_PREPROCESSOR_MACRODEF_ARRAY; return fLocationResolver.getMacroDefinitions(); } - + + /* (non-Javadoc) + * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getMacroExpansions() + */ + public IASTPreprocessorMacroExpansion[] getMacroExpansions() { + if (fLocationResolver == null) + return IASTPreprocessorMacroExpansion.EMPTY_ARRAY; + return fLocationResolver.getMacroExpansions(getFileLocation()); + } + /* * (non-Javadoc) * - * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getMacroDefinitions() + * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getBuiltinMacroDefinitions() */ public final IASTPreprocessorMacroDefinition[] getBuiltinMacroDefinitions() { if (fLocationResolver == null) @@ -316,20 +327,10 @@ public abstract class ASTTranslationUnit extends ASTNode implements IASTTranslat * @see org.eclipse.cdt.core.dom.ast.IASTTranslationUnit#getNodeForLocation(org.eclipse.cdt.core.dom.ast.IASTNodeLocation) */ public final IASTNode selectNodeForLocation(String path, int realOffset, int realLength) { - IASTNode result= null; - if (fLocationResolver != null) { - int start= fLocationResolver.getSequenceNumberForFileOffset(path, realOffset); - if (start >= 0) { - int length= realLength < 1 ? 0 : - fLocationResolver.getSequenceNumberForFileOffset(path, realOffset+realLength-1) + 1 - start; - result= fLocationResolver.findSurroundingPreprocessorNode(start, length); - if (result == null) { - FindNodeForOffsetAction nodeFinder = new FindNodeForOffsetAction(start, length); - accept(nodeFinder); - result = nodeFinder.getNode(); - } - } - } - return result; + return getNodeSelector(path).findNode(realOffset, realLength); + } + + public final IASTNodeSelector getNodeSelector(String filePath) { + return new ASTNodeSelector(this, fLocationResolver, filePath); } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FindNodeForOffsetAction.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FindNodeForOffsetAction.java index a42d41926e6..143d932905d 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FindNodeForOffsetAction.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/dom/parser/FindNodeForOffsetAction.java @@ -39,49 +39,47 @@ import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTVisitor; import org.eclipse.cdt.core.dom.ast.cpp.ICPPASTCompositeTypeSpecifier.ICPPASTBaseSpecifier; public class FindNodeForOffsetAction extends CPPASTVisitor implements ICASTVisitor, ICPPASTVisitor { - private IASTNode fFoundNode = null; - private int fOffset = 0; - private int fLength = 0; + private ASTNode fCandidate= null; + private final int fOffset; + private final int fLength; + private final ASTNodeMatchKind fMatchKind; - public FindNodeForOffsetAction(int offset, int length) { + public FindNodeForOffsetAction(int offset, int length, ASTNodeMatchKind matchKind) { + fMatchKind= matchKind; fOffset = offset; fLength = length; shouldVisitNames = true; - shouldVisitDeclarations = true; - shouldVisitInitializers = true; - shouldVisitParameterDeclarations = true; - shouldVisitDeclarators = true; - shouldVisitDeclSpecifiers = true; - shouldVisitDesignators = true; - shouldVisitEnumerators = true; - shouldVisitExpressions = true; - shouldVisitStatements = true; - shouldVisitTypeIds = true; - shouldVisitEnumerators = true; - shouldVisitBaseSpecifiers = true; - shouldVisitNamespaces = true; - shouldVisitTemplateParameters= true; - shouldVisitTranslationUnit= true; + shouldVisitDeclarations= true; + + shouldVisitInitializers= + shouldVisitParameterDeclarations= + shouldVisitDeclarators= + shouldVisitDeclSpecifiers= + shouldVisitDesignators= + shouldVisitEnumerators= + shouldVisitExpressions= + shouldVisitStatements= + shouldVisitTypeIds= + shouldVisitEnumerators= + shouldVisitBaseSpecifiers= + shouldVisitNamespaces= + shouldVisitTemplateParameters= + shouldVisitTranslationUnit= !matchKind.matchNamesOnly(); } public int processNode(IASTNode node) { - if (fFoundNode != null) - return PROCESS_ABORT; - if (node instanceof ASTNode) { - final int offset = ((ASTNode) node).getOffset(); - final int length = ((ASTNode) node).getLength(); - - if (offset == fOffset && length == fLength) { - fFoundNode = node; - return PROCESS_ABORT; + final ASTNode astNode = (ASTNode) node; + if (astNode.getOffset() > fOffset+fLength || astNode.getOffset() + astNode.getLength() < fOffset) { + return PROCESS_SKIP; } - // skip the rest of this node if the selection is outside of its - // bounds - if (fOffset > offset + length) - return PROCESS_SKIP; + if (fMatchKind.matches(astNode, fOffset, fLength)) { + if (fCandidate == null || !fMatchKind.isBetterMatch(fCandidate, astNode)) { + fCandidate= astNode; + } + } } return PROCESS_CONTINUE; } @@ -90,8 +88,7 @@ public class FindNodeForOffsetAction extends CPPASTVisitor implements ICASTVisit public int visit(IASTDeclaration declaration) { // use declarations to determine if the search has gone past the // offset (i.e. don't know the order the visitor visits the nodes) - if (declaration instanceof ASTNode - && ((ASTNode) declaration).getOffset() > fOffset) + if (declaration instanceof ASTNode && ((ASTNode) declaration).getOffset() > fOffset + fLength) return PROCESS_ABORT; return processNode(declaration); @@ -208,7 +205,7 @@ public class FindNodeForOffsetAction extends CPPASTVisitor implements ICASTVisit return processNode(tu); } - public IASTNode getNode() { - return fFoundNode; + public ASTNode getNode() { + return fCandidate; } }
\ No newline at end of file |