/*******************************************************************************
* Copyright (c) 2005, 2012 eBay Inc.
* 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
*
*******************************************************************************/
/**
*
*/
package org.eclipse.vjet.eclipse.core.search;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.vjet.dsf.jst.IJstGlobalVar;
import org.eclipse.vjet.dsf.jst.IJstMethod;
import org.eclipse.vjet.dsf.jst.IJstNode;
import org.eclipse.vjet.dsf.jst.IJstProperty;
import org.eclipse.vjet.dsf.jst.IJstType;
import org.eclipse.vjet.dsf.jst.declaration.JstArg;
import org.eclipse.vjet.dsf.jst.declaration.JstMethod;
import org.eclipse.vjet.dsf.jst.declaration.JstVar;
import org.eclipse.vjet.dsf.jst.declaration.JstVars;
import org.eclipse.vjet.dsf.jst.expr.FieldAccessExpr;
import org.eclipse.vjet.dsf.jst.term.JstIdentifier;
import org.eclipse.vjet.dsf.jst.traversal.JstDepthFirstTraversal;
import org.eclipse.vjet.dsf.ts.property.PropertyName;
import org.eclipse.vjet.dsf.ts.type.TypeName;
import org.eclipse.vjet.eclipse.codeassist.CodeassistUtils;
import org.eclipse.vjet.eclipse.core.IVjoSourceModule;
import org.eclipse.vjet.eclipse.core.VjetPlugin;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceMgr;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.dltk.mod.core.Flags;
import org.eclipse.dltk.mod.core.IField;
import org.eclipse.dltk.mod.core.IModelElement;
import org.eclipse.dltk.mod.core.ISourceRange;
import org.eclipse.dltk.mod.core.IType;
import org.eclipse.dltk.mod.core.ModelException;
import org.eclipse.dltk.mod.core.search.SearchPattern;
import org.eclipse.dltk.mod.internal.core.NativeVjoSourceModule;
import org.eclipse.dltk.mod.internal.core.search.matching.FieldPattern;
/**
* Search field/variables declaration and references.
*
*
*
*/
class VjoFieldSearcher extends AbstractVjoElementSearcher {
public static final int TYPE_PROP = 2;
public static final int LOCAL_VAR = 1;
public static final int METHOD_ARG = 0;
/*
* (non-Javadoc)
*
* @see org.eclipse.vjet.eclipse.core.search.IVjoElementSearcher#getSearchPatternClass()
*/
public Class<? extends SearchPattern> getSearchPatternClass() {
return FieldPattern.class;
}
/**
* Request local variable references from methods arguments and identifiers.
*
*
*
*/
private class LocalVarRefsRequestor {
private List<IJstNode> refs = new LinkedList<IJstNode>();
private String name = null;
/**
* Accept {@link IJstNode} for search local variable references.
*
* @param node
*/
public void accept(IJstNode node) {
if (node == null) {
return;
}
// System.out.println(node.toString());
if (node instanceof JstIdentifier) {
JstIdentifier identifier = (JstIdentifier) node;
if (identifier.getName().equals(name)) {
refs.add(identifier);
}
} else if (node instanceof JstVar) {
// skip declarations
return;
} else if (node instanceof JstMethod) {
List<JstArg> args = ((JstMethod) node).getArgs();
for (JstArg jstArg : args) {
if (name.equals(jstArg.getName())) {
refs.add(jstArg);
}
}
}
List<? extends IJstNode> children = node.getChildren();
if (children != null && children.size() > 0) {
for (IJstNode jstNode : children) {
if (jstNode instanceof FieldAccessExpr) {
// for local var, it would not exist in FieldAccessExpr
continue;
}
accept(jstNode);
}
}
}
/**
* Create instance of this class with name of the local variable.
*
* @param name
* name of the local variable.
*/
public LocalVarRefsRequestor(String name) {
super();
this.name = name;
}
/**
* Returns list of the found local variable references.
*
* @return list of the found local variable references.
*/
public List<IJstNode> getRefs() {
return refs;
}
/**
* Returns name of the local variable.
*
* @return name of the local variable.
*/
public String getName() {
return name;
}
}
@Override
protected void searchDeclarations(SearchQueryParameters params,
List<VjoMatch> result) {
IField element = (IField) params.getElement();
IVjoSourceModule module = (IVjoSourceModule) element.getSourceModule();
IField field = findFieldDeclaration(element, module);
TypeName typeName = module.getTypeName();
IType type = CodeassistUtils.findResourceType(module, typeName
.typeName());
if (isInScope(type) && field != null) {
try {
ISourceRange nameRange = field.getNameRange();
VjoMatch match = VjoMatchFactory.createMethodMatch(type,
nameRange.getOffset(), nameRange.getLength());
result.add(match);
// Add by Oliver.2009-06-25.
try {
match.setIsPublic(Flags.isPublic(field.getFlags()));
match.setIsStatic(Flags.isStatic(field.getFlags()));
} catch (ModelException e) {
}
// searchCommentDeclarition(typeName, nameRange);
} catch (ModelException e) {
VjetPlugin.getDefault().getLog().log(
new Status(IStatus.ERROR, VjetPlugin.PLUGIN_ID,
IStatus.ERROR, "Wrong name range", e));
}
}
}
/**
* Find field declaration for the field reference element
*
* @param element
* field reference element
* @param module
* source module
* @return field declaration object.
*/
private IField findFieldDeclaration(IField element, IVjoSourceModule module) {
IField field = null;
try {
int offset = element.getNameRange().getOffset();
IModelElement parent = module.getElementAt(offset);
if (parent == null) {
return null;
}
if (parent instanceof IField) {
field = (IField) parent;
} else {
String name = element.getElementName();
field = (IField) CodeassistUtils.findChild(name, parent);
}
} catch (ModelException e1) {
// DLTKCore.error(e1.toString(), e1);
}
return field;
}
@Override
protected void searchReferences(SearchQueryParameters params,
List<VjoMatch> result) {
IField field = (IField) params.getElement();
if (this.isLocal(field)) {
IJstMethod jstMethod = this.getJstMethod(field);
this.findRefs(field, jstMethod, result);
} else {
if (field.getSourceModule() instanceof NativeVjoSourceModule)
this.processNativeTypeField(field, result);
else
this.processSourceTypeField(field, result);
}
}
// process type field reference in source type, even in inner source type
private void processSourceTypeField(IField field, List<VjoMatch> result) {
IJstProperty jstProperty = this.getJstProperty(field);
if (jstProperty == null)
return;
// work out PropertyName and find referenced nodes from TypeSpaceMgr
String grouName = jstProperty.getOwnerType().getPackage()
.getGroupName();
String typeName = jstProperty.getOwnerType().getName();
PropertyName propertyName = new PropertyName(new TypeName(grouName,
typeName), field.getElementName());
List<IJstNode> list = mgr.getPropertyDependents(propertyName);
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
IJstNode jstNode = (IJstNode) iterator.next();
this.findRefs(field, jstNode, result);
}
}
// process type field reference in native type
private void processNativeTypeField(IField field, List<VjoMatch> result) {
NativeVjoSourceModule nativeVjoSourceModule = (NativeVjoSourceModule) field
.getSourceModule();
String groupName = nativeVjoSourceModule.getTypeName().groupName();
String typeName = nativeVjoSourceModule.getTypeName().typeName();
PropertyName propertyName = new PropertyName(new TypeName(groupName,
typeName), field.getElementName());
List<IJstNode> list = mgr.getPropertyDependents(propertyName);
for (Iterator iterator = list.iterator(); iterator.hasNext();) {
IJstNode jstNode = (IJstNode) iterator.next();
this.findRefs(field, jstNode, result);
}
}
// pass request to VjoFieldReferenceVistor
private void findRefs(IField field, IJstNode searchNode,
List<VjoMatch> result) {
if (searchNode == null)
return;
VjoFieldReferenceVistor fieldReferenceVistor = new VjoFieldReferenceVistor(
field, searchNode, result);
JstDepthFirstTraversal.accept(searchNode, fieldReferenceVistor);
}
/**
* determine whether is local (including var and arg)
*
* @param field
* @return
*/
private boolean isLocal(IField field) {
if (field.getParent().getElementType() == IModelElement.METHOD)
return true;
else
return false;
}
/**
* get correct corresponding jst method (iterating inner type)
*
* @param field
* @return
*/
private IJstMethod getJstMethod(IField field) {
// first, work out root jst type (outer type)
IVjoSourceModule module = (IVjoSourceModule) field.getSourceModule();
TypeName jstTypeName = module.getTypeName();
IJstType jstType = TypeSpaceMgr.findType(jstTypeName.groupName(),
jstTypeName.typeName());
// second, work out dltk type name
IType type = (IType) field.getParent().getParent();
String dltkTypeName = type.getFullyQualifiedName(".");
// fetch the jst method (maybe a sub method of inner type)
return this.getJstMethod(jstType, dltkTypeName, field.getParent()
.getElementName());
}
// currently, not support anoymous inner type
private IJstMethod getJstMethod(IJstType type, String typeName,
String methodName) {
if (type.getAlias().equals(typeName)) {
IJstMethod jstMethod = type.getMethod(methodName);
if (jstMethod == null && "constructs".equals(methodName))
jstMethod = type.getConstructor();
return jstMethod;
} else {
// iterate inner types...
for (Iterator iterator = type.getEmbededTypes().iterator(); iterator
.hasNext();) {
IJstType innerType = (IJstType) iterator.next();
IJstMethod jstMethod = this.getJstMethod(innerType, typeName,
methodName);
if (jstMethod != null)
return jstMethod;
}
}
return null;
}
/**
* get correct corresponding jst property
*
* @param field
* @return
*/
private IJstProperty getJstProperty(IField field) {
// first, work out root jst type (outer type)
IVjoSourceModule module = (IVjoSourceModule) field.getSourceModule();
TypeName jstTypeName = module.getTypeName();
IJstType jstType = TypeSpaceMgr.findType(jstTypeName.groupName(),
jstTypeName.typeName());
// second, work out dltk type name
if(!(field.getParent() instanceof IType) && field instanceof IField){
field = (IField) field.getParent();
}
String dltkTypeName = ((IType) field.getParent())
.getFullyQualifiedName(".");
return this.getJstProperty(jstType, dltkTypeName, field
.getElementName());
}
// currently, not support anoymous inner type
private IJstProperty getJstProperty(IJstType type, String typeName,
String propertyName) {
if (type.getAlias().equals(typeName)) {
IJstProperty jstProperty = type.getProperty(propertyName);
IJstGlobalVar globalVar = type.getGlobalVar(propertyName);
if(jstProperty==null && globalVar!=null){
return globalVar.getProperty();
}
return jstProperty;
} else {
// iterate inner types...
for (Iterator iterator = type.getEmbededTypes().iterator(); iterator
.hasNext();) {
IJstType innerType = (IJstType) iterator.next();
IJstProperty jstProperty = this.getJstProperty(innerType,
typeName, propertyName);
if (jstProperty != null)
return jstProperty;
}
}
return null;
}
// add by patrick
/*
* (non-Javadoc)
*
* @see org.eclipse.vjet.eclipse.core.search.AbstractVjoElementSearcher#findOccurrence(org.eclipse.vjet.dsf.jst.IJstNode,
* org.eclipse.vjet.dsf.jst.IJstNode)
*/
@Override
public List<VjoMatch> findOccurrence(IJstNode jstNode, IJstNode scope) {
int fieldType = -1;
if (jstNode instanceof JstArg) {
fieldType = METHOD_ARG;
} else if (jstNode instanceof JstVars) {
fieldType = LOCAL_VAR;
} else if (jstNode instanceof IJstProperty) {
fieldType = TYPE_PROP;
} else {
VjetPlugin.error("Unhandled field node type in occurrence marking:"
+ jstNode.getClass().getName());
return Collections.emptyList();
}
IJstNode searchedTree = scope;
// search from method/constructor tree only if not type property
if (isLocal(fieldType)) {
searchedTree = CodeassistUtils.findDeclaringMethod(jstNode);
}
if (searchedTree == null) {
return Collections.emptyList();
}
return findOccurrence(fieldType, jstNode, searchedTree);
}
private boolean isLocal(int fieldType) {
return TYPE_PROP != fieldType;
}
private List<VjoMatch> findOccurrence(int fieldType, IJstNode matchNode,
IJstNode jstTree) {
AbstractVjoOccurrenceVisitor visitor = new VjoFieldOccurrenceVisitor(fieldType,
matchNode);
jstTree.accept(visitor);
return visitor.getMatches();
}
// end add
}