| /******************************************************************************* |
| * Copyright (c) 2005, 2016 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| *******************************************************************************/ |
| package org.eclipse.dltk.ruby.internal.core.search; |
| |
| import org.eclipse.dltk.ast.ASTNode; |
| import org.eclipse.dltk.ast.declarations.FieldDeclaration; |
| import org.eclipse.dltk.ast.declarations.MethodDeclaration; |
| import org.eclipse.dltk.ast.declarations.TypeDeclaration; |
| import org.eclipse.dltk.ast.expressions.BigNumericLiteral; |
| import org.eclipse.dltk.ast.expressions.BooleanLiteral; |
| import org.eclipse.dltk.ast.expressions.CallExpression; |
| import org.eclipse.dltk.ast.expressions.FloatNumericLiteral; |
| import org.eclipse.dltk.ast.expressions.Literal; |
| import org.eclipse.dltk.ast.expressions.NilLiteral; |
| import org.eclipse.dltk.ast.expressions.NumericLiteral; |
| import org.eclipse.dltk.ast.expressions.StringLiteral; |
| import org.eclipse.dltk.ast.references.ConstantReference; |
| import org.eclipse.dltk.ast.references.Reference; |
| import org.eclipse.dltk.ast.references.SimpleReference; |
| import org.eclipse.dltk.ast.references.TypeReference; |
| import org.eclipse.dltk.ast.references.VariableReference; |
| import org.eclipse.dltk.core.search.matching.MatchLocator; |
| import org.eclipse.dltk.core.search.matching.MatchLocatorParser; |
| import org.eclipse.dltk.core.search.matching.PatternLocator; |
| import org.eclipse.dltk.ruby.ast.IRubyASTVisitor; |
| import org.eclipse.dltk.ruby.ast.RubyAliasExpression; |
| import org.eclipse.dltk.ruby.ast.RubyAssignment; |
| import org.eclipse.dltk.ruby.ast.RubyColonExpression; |
| import org.eclipse.dltk.ruby.ast.RubyConstantDeclaration; |
| import org.eclipse.dltk.ruby.ast.RubyRegexpExpression; |
| import org.eclipse.dltk.ruby.ast.RubySymbolReference; |
| |
| public class RubyMatchLocatorParser extends MatchLocatorParser { |
| |
| public RubyMatchLocatorParser(MatchLocator locator) { |
| super(locator); |
| } |
| |
| static boolean locationEquals(ASTNode node, Object obj) { |
| if (obj == node) |
| return true; |
| if (obj instanceof ASTNode) { |
| return node.locationMatches((ASTNode) obj); |
| } |
| return false; |
| } |
| |
| private static final class TypeReferenceLocation extends TypeReference { |
| private TypeReferenceLocation(int start, int end, String name) { |
| super(start, end, name); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| return locationEquals(this, obj); |
| } |
| |
| @Override |
| public int hashCode() { |
| return this.sourceEnd() * 1001 + this.sourceEnd(); |
| } |
| } |
| |
| private static final class MethodDeclarationLocation extends |
| MethodDeclaration { |
| private MethodDeclarationLocation(String name, int nameStart, |
| int nameEnd, int declStart, int declEnd) { |
| super(name, nameStart, nameEnd, declStart, declEnd); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| return locationEquals(this, obj); |
| } |
| |
| @Override |
| public int hashCode() { |
| return this.sourceEnd() * 1001 + this.sourceEnd(); |
| } |
| } |
| |
| private static final class FieldDeclarationLocation extends |
| FieldDeclaration { |
| private FieldDeclarationLocation(String name, int nameStart, |
| int nameEnd, int declStart, int declEnd) { |
| super(name, nameStart, nameEnd, declStart, declEnd); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| return locationEquals(this, obj); |
| } |
| |
| @Override |
| public int hashCode() { |
| return this.sourceEnd() * 1001 + this.sourceEnd(); |
| } |
| } |
| |
| private static final class SimpleReferenceLocation extends SimpleReference { |
| private SimpleReferenceLocation(int start, int end, String name) { |
| super(start, end, name); |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| return locationEquals(this, obj); |
| } |
| |
| @Override |
| public int hashCode() { |
| return this.sourceEnd() * 1001 + this.sourceEnd(); |
| } |
| } |
| |
| protected class RubyMatchVisitor extends MatchVisitor implements |
| IRubyASTVisitor { |
| |
| @Override |
| public void visitTypeName(ASTNode node) { |
| // empty |
| } |
| |
| } |
| |
| @Override |
| protected MatchVisitor getMatchVisitor() { |
| return new RubyMatchVisitor(); |
| } |
| |
| private void reportTypeReferenceMatch(ASTNode node, PatternLocator locator) { |
| String typeName; |
| while (node != null) { |
| if (node instanceof RubyColonExpression) { |
| typeName = ((RubyColonExpression) node).getName(); |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), typeName); |
| locator.match(ref, this.getNodeSet()); |
| node = ((RubyColonExpression) node).getLeft(); |
| } else if (node instanceof ConstantReference) { |
| typeName = ((ConstantReference) node).getName(); |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), typeName); |
| locator.match(ref, this.getNodeSet()); |
| node = null; |
| } else { |
| node = null; |
| } |
| } |
| } |
| |
| private void reportSimpleReferenceMatch(SimpleReference simpleRef, |
| PatternLocator locator) { |
| int pos = simpleRef.sourceStart(); |
| if (pos < 0) { |
| pos = 0; |
| } |
| locator.match(new SimpleReferenceLocation(pos, pos |
| + simpleRef.getName().length(), simpleRef.getName()), |
| this.getNodeSet()); |
| } |
| |
| @Override |
| protected void processStatement(ASTNode node, PatternLocator locator) { |
| if (node == null) { |
| return; |
| } |
| if (node instanceof CallExpression) { |
| CallExpression call = (CallExpression) node; |
| // int start = call.sourceStart(); |
| // int end = call.sourceEnd(); |
| // if (start < 0) { |
| // start = 0; |
| // } |
| // if (end < 0) { |
| // end = 1; |
| // } |
| locator.match(call, this.getNodeSet()); |
| /* |
| * (CallExpression) new CallExpression(start, end, |
| * call.getReceiver(), call.getName(), call.getArgs()) |
| */ |
| } else if (node instanceof RubyAliasExpression) { |
| final RubyAliasExpression alias = (RubyAliasExpression) node; |
| final MethodDeclaration method = new MethodDeclarationLocation( |
| alias.getNewValue(), alias.sourceStart(), |
| alias.sourceEnd(), alias.sourceStart(), alias.sourceEnd()); |
| locator.match(method, this.getNodeSet()); |
| } else if (node instanceof RubyAssignment) { |
| // Assignment handling (this is static variable assignment.) |
| |
| RubyAssignment assignment = (RubyAssignment) node; |
| ASTNode left = assignment.getLeft(); |
| if (left instanceof VariableReference) { |
| VariableReference var = (VariableReference) left; |
| FieldDeclaration field = new FieldDeclarationLocation( |
| var.getName(), var.sourceStart(), var.sourceEnd() - 1, |
| var.sourceStart(), var.sourceEnd() - 1); |
| locator.match(field, this.getNodeSet()); |
| } |
| } else if (node instanceof Literal) { |
| if (node instanceof RubyRegexpExpression) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "Regexp"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof StringLiteral) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "String"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof BooleanLiteral) { |
| BooleanLiteral boolLit = (BooleanLiteral) node; |
| TypeReference ref; |
| if (boolLit.boolValue()) { |
| ref = new TypeReferenceLocation(node.sourceStart(), |
| node.sourceEnd(), "TrueClass"); //$NON-NLS-1$ |
| } else { |
| ref = new TypeReferenceLocation(node.sourceStart(), |
| node.sourceEnd(), "FalseClass"); //$NON-NLS-1$ |
| } |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof NumericLiteral) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "Fixnum"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof NilLiteral) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "NilClass"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof FloatNumericLiteral) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "Float"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof BigNumericLiteral) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "Bignum"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } |
| } else if (node instanceof Reference) { |
| if (node instanceof RubySymbolReference) { |
| TypeReference ref = new TypeReferenceLocation( |
| node.sourceStart(), node.sourceEnd(), "Symbol"); //$NON-NLS-1$ |
| locator.match(ref, this.getNodeSet()); |
| } else if (node instanceof VariableReference) { |
| reportSimpleReferenceMatch((SimpleReference) node, locator); |
| } else if (node instanceof ConstantReference) { |
| reportSimpleReferenceMatch((SimpleReference) node, locator); |
| reportTypeReferenceMatch(node, locator); |
| } |
| } else if (node instanceof RubyColonExpression) { |
| reportTypeReferenceMatch(node, locator); |
| } else if (node instanceof RubyConstantDeclaration) { |
| RubyConstantDeclaration var = (RubyConstantDeclaration) node; |
| SimpleReference name = var.getName(); |
| FieldDeclaration field = new FieldDeclarationLocation( |
| name.getName(), name.sourceStart(), name.sourceEnd(), |
| name.sourceStart(), name.sourceEnd()); |
| locator.match(field, this.getNodeSet()); |
| } |
| } |
| |
| @Override |
| protected TypeReference createSuperTypeReference(TypeDeclaration t, |
| ASTNode superClass) { |
| String name = t.resolveSuperClassReference(superClass); |
| if (name != null) { |
| initPatternProcessor(); |
| if (patternProcessor != null) { |
| name = patternProcessor.extractTypeChars(name); |
| } |
| // TODO create QualifiedTypeReference if needed |
| return new TypeReferenceLocation(superClass.sourceStart(), |
| superClass.sourceEnd(), name); |
| } else { |
| return null; |
| } |
| } |
| } |