package org.rubypeople.rdt.internal.core.search.matching; import org.eclipse.core.runtime.CoreException; import org.jruby.ast.ConstNode; import org.jruby.ast.Node; import org.rubypeople.rdt.core.IRubyElement; import org.rubypeople.rdt.core.RubyCore; import org.rubypeople.rdt.core.RubyModelException; import org.rubypeople.rdt.core.search.SearchPattern; import org.rubypeople.rdt.internal.core.RubyScript; import org.rubypeople.rdt.internal.core.parser.InOrderVisitor; import org.rubypeople.rdt.internal.core.parser.RubyParser; import org.rubypeople.rdt.internal.core.util.CharOperation; public class TypeReferenceLocator extends PatternLocator { private TypeReferencePattern pattern; public TypeReferenceLocator(TypeReferencePattern pattern) { super(pattern); this.pattern = pattern; } @Override public void reportMatches(RubyScript script, MatchLocator locator) { Node ast = script.lastGoodAST; if (ast == null) { try { ast = new RubyParser().parse(script.getSource()).getAST(); } catch (RubyModelException e) { RubyCore.log(e); } } InOrderVisitor visitor = new TypeRefASTVisitor(script, pattern, locator); visitor.acceptNode(ast); } private class TypeRefASTVisitor extends InOrderVisitor { private TypeReferencePattern pattern; private MatchLocator locator; private RubyScript script; public TypeRefASTVisitor(RubyScript script, TypeReferencePattern pattern, MatchLocator locator) { this.script = script; this.pattern = pattern; this.locator = locator; } private int resolveLevel(char[] sourceName) { char[] qualifiedPattern = getQualifiedPattern(pattern.simpleName, pattern.qualification); if (sourceName == null) return IMPOSSIBLE_MATCH; if ((pattern.matchMode & SearchPattern.R_PREFIX_MATCH) != 0) { if (CharOperation.prefixEquals(qualifiedPattern, sourceName, pattern.isCaseSensitive)) { return ACCURATE_MATCH; } } if (pattern.isCamelCase) { if (!pattern.isCaseSensitive || (qualifiedPattern.length>0 && sourceName.length>0 && qualifiedPattern[0] == sourceName[0])) { if (CharOperation.camelCaseMatch(qualifiedPattern, sourceName)) { return ACCURATE_MATCH; } } if (pattern.matchMode == SearchPattern.R_EXACT_MATCH) { boolean matchPattern = CharOperation.prefixEquals(qualifiedPattern, sourceName, pattern.isCaseSensitive); return matchPattern ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; } } boolean matchPattern = CharOperation.match(qualifiedPattern, sourceName, pattern.isCaseSensitive); return matchPattern ? ACCURATE_MATCH : IMPOSSIBLE_MATCH; } protected char[] getQualifiedPattern(char[] simpleNamePattern, char[] qualificationPattern) { // NOTE: if case insensitive search then simpleNamePattern & qualificationPattern are assumed to be lowercase if (simpleNamePattern == null) { if (qualificationPattern == null) return null; return CharOperation.concat(qualificationPattern, ONE_STAR, "::"); } else if (qualificationPattern == null) { return simpleNamePattern; } else { return CharOperation.concat(qualificationPattern, simpleNamePattern, "::"); } } @Override public Object visitConstNode(ConstNode iVisited) { String constantName = iVisited.getName(); int accuracy = resolveLevel(constantName.toCharArray()); if (accuracy != IMPOSSIBLE_MATCH) { try { IRubyElement enclosingElement = script.getElementAt(iVisited.getPosition().getStartOffset()); // FIXME Fix the accuracy level to A_ACCURATE OR A_INACCURATE locator.report(locator.newTypeReferenceMatch(enclosingElement, accuracy, iVisited.getPosition().getStartOffset(), iVisited.getPosition().getEndOffset() - iVisited.getPosition().getStartOffset())); } catch (CoreException e) { RubyCore.log(e); } } return super.visitConstNode(iVisited); } } }