/*******************************************************************************
* Copyright (c) 2007-2013 Red Hat, Inc.
* Distributed under license by Red Hat, Inc. All rights reserved.
* This program is 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:
* Red Hat, Inc. - initial API and implementation
******************************************************************************/
package org.jboss.tools.common.el.core.ca;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.jboss.tools.common.el.core.ELCorePlugin;
import org.jboss.tools.common.el.core.ELReference;
import org.jboss.tools.common.el.core.model.ELArgument;
import org.jboss.tools.common.el.core.model.ELArgumentInvocation;
import org.jboss.tools.common.el.core.model.ELExpression;
import org.jboss.tools.common.el.core.model.ELInstance;
import org.jboss.tools.common.el.core.model.ELInvocationExpression;
import org.jboss.tools.common.el.core.model.ELMethodInvocation;
import org.jboss.tools.common.el.core.model.ELModel;
import org.jboss.tools.common.el.core.model.ELObject;
import org.jboss.tools.common.el.core.model.ELObjectType;
import org.jboss.tools.common.el.core.model.ELPropertyInvocation;
import org.jboss.tools.common.el.core.model.ELUtil;
import org.jboss.tools.common.el.core.parser.ELParser;
import org.jboss.tools.common.el.core.parser.ELParserFactory;
import org.jboss.tools.common.el.core.parser.ELParserUtil;
import org.jboss.tools.common.el.core.parser.LexicalToken;
import org.jboss.tools.common.el.core.resolver.ELCompletionEngine;
import org.jboss.tools.common.el.core.resolver.ELContext;
import org.jboss.tools.common.el.core.resolver.ELResolution;
import org.jboss.tools.common.el.core.resolver.ELResolutionImpl;
import org.jboss.tools.common.el.core.resolver.ELResolver;
import org.jboss.tools.common.el.core.resolver.ELSegment;
import org.jboss.tools.common.el.core.resolver.ELSegmentImpl;
import org.jboss.tools.common.el.core.resolver.ElVarSearcher;
import org.jboss.tools.common.el.core.resolver.IRelevanceCheck;
import org.jboss.tools.common.el.core.resolver.IVariable;
import org.jboss.tools.common.el.core.resolver.JavaMemberELSegment;
import org.jboss.tools.common.el.core.resolver.JavaMemberELSegmentImpl;
import org.jboss.tools.common.el.core.resolver.TypeInfoCollector;
import org.jboss.tools.common.el.core.resolver.TypeInfoCollector.MemberInfo;
import org.jboss.tools.common.el.core.resolver.TypeInfoCollector.MemberPresentation;
import org.jboss.tools.common.el.core.resolver.Var;
import org.jboss.tools.common.el.internal.core.parser.token.JavaNameTokenDescription;
import org.jboss.tools.common.el.internal.core.parser.token.WhiteSpaceTokenDescription;
import org.jboss.tools.common.text.TextProposal;
import org.jboss.tools.common.util.BeanUtil;
public abstract class AbstractELCompletionEngine<V extends IVariable> implements ELResolver, ELCompletionEngine {
private static final List<Var> EMPTY_VARS = Collections.unmodifiableList(new ArrayList<Var>());
protected final List<V> EMPTY_VARIABLES_LIST = Collections.unmodifiableList(new ArrayList<V>());
public static final IRelevanceCheck IRRELEVANT = new IRelevanceCheck() {
public boolean isRelevant(String content) {
return false;
}
};
public AbstractELCompletionEngine() {}
protected abstract ImageDescriptor getELProposalImageForMember(MemberInfo memberInfo);
protected abstract void log(Exception e);
private static ELParserFactory defaultFactory = ELParserUtil.getJbossFactory();
protected ImageDescriptor getELProposalImage(MemberPresentation memberPresentation) {
return getELProposalImageForMember(memberPresentation!=null?memberPresentation.getMember():null);
}
/* (non-Javadoc)
* @see org.jboss.tools.common.el.core.resolver.ELResolver#getProposals(org.jboss.tools.common.el.core.resolver.ELContext, int)
*/
public List<TextProposal> getProposals(ELContext context, int offset) {
ELReference ref = context.getELReference(offset);
if(ref!=null) {
for (ELExpression expresion : ref.getEl()) {
if(ref.getStartPosition() + expresion.getStartPosition()<=offset && (ref.getStartPosition() + expresion.getEndPosition()>=offset)) {
ELInvocationExpression ie = ELUtil.findExpression(expresion.getModel(), offset - ref.getStartPosition());
String el = "#{"; //$NON-NLS-1$
if(ie!=null) {
el = el + ref.getSourceText().substring(ie.getStartPosition(), offset - ref.getStartPosition());
}
return getProposals(context, el, offset);
}
}
List<ELInstance> is = ref.getELModel().getInstances();
for (ELInstance i: is) {
ELExpression exp = i.getExpression();
if(exp == null || exp.getFirstToken() == null) {
continue;
}
LexicalToken b = exp.getFirstToken();
while(b.getPreviousToken() != null && b.getPreviousToken().getType() == WhiteSpaceTokenDescription.WHITESPACE) {
b = b.getPreviousToken();
}
LexicalToken e = exp.getLastToken();
if(e == null) e = b;
while(e.getNextToken() != null && e.getNextToken().getType() == WhiteSpaceTokenDescription.WHITESPACE) {
e = e.getNextToken();
}
if(exp != null && ref.getStartPosition() + b.getStart() <= offset && ref.getStartPosition() + e.getStart() + e.getLength() >= offset) {
return getProposals(context, "#{", offset); //$NON-NLS-1$
}
}
}
return Collections.emptyList();
}
/*
* (non-Javadoc)
* @see org.jboss.tools.common.el.core.resolver.ELResolver2#getProposals(org.jboss.tools.common.el.core.resolver.ELContext, java.lang.String)
*/
public List<TextProposal> getProposals(ELContext context, String el, int offset) {
List<TextProposal> completions = new ArrayList<TextProposal>();
List<Var> vars = context.getVarsAsList(offset);
ELResolutionImpl resolution;
try {
resolution = resolveELOperand(context.getResource(), context, parseOperand(el), false, vars, new ElVarSearcher(context.getResource(), this), offset);
if(resolution!=null) {
completions.addAll(resolution.getProposals());
}
} catch (StringIndexOutOfBoundsException e) {
log(e);
} catch (BadLocationException e) {
log(e);
}
return completions;
}
public IRelevanceCheck createRelevanceCheck(IJavaElement element) {
return new DefaultJavaRelevanceCheck(element);
}
/*
* (non-Javadoc)
* @see org.jboss.tools.common.el.core.resolver.ELResolver#resolve(org.jboss.tools.common.el.core.resolver.ELContext, org.jboss.tools.common.el.core.model.ELExpression)
*/
public ELResolution resolve(ELContext context, ELExpression operand, int offset) {
List<Var> vars = context.getVarsAsList(offset);
ELResolutionImpl resolution = null;
try {
resolution = resolveELOperand(context.getResource(), context, operand, true, vars, new ElVarSearcher(context.getResource(), this), offset);
if(resolution != null)
resolution.setContext(context);
} catch (StringIndexOutOfBoundsException e) {
log(e);
} catch (BadLocationException e) {
log(e);
}
return resolution;
}
/**
* Resolves EL Operand
*
* @param operand
* @param context
* @param returnEqualedVariablesOnly
* @return
*/
public ELResolution resolveELOperand(ELExpression operand, ELContext context, boolean returnEqualedVariablesOnly, int offset) {
List<Var> vars = context.getVarsAsList(offset);
try {
return resolveELOperand(context.getResource(), context, operand, returnEqualedVariablesOnly, vars, new ElVarSearcher(context.getResource(), this), offset);
} catch (StringIndexOutOfBoundsException e) {
log(e);
} catch (BadLocationException e) {
log(e);
}
return null;
}
public ELExpression parseOperand(String operand) {
return parseOperand(operand, getParserFactory());
}
public ELExpression parseOperand(String operand, ELParserFactory factory) {
if(operand == null || factory == null) return null;
String el = (operand.indexOf("#{") < 0 && operand.indexOf("${") < 0) ? "#{" + operand + "}" : operand; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
ELParser p = factory.createParser();
ELModel model = p.parse(el);
List<ELInstance> is = model.getInstances();
if(is.isEmpty()) return null;
return is.get(0).getExpression();
}
protected static final String collectionAdditionForCollectionDataModel = ".iterator().next()"; //$NON-NLS-1$
protected static final String collectionAdditionForMapDataModel = ".entrySet().iterator().next()"; //$NON-NLS-1$
protected List<String> getVarNameProposals(List <Var> vars, String prefix) {
List<String> proposals = new ArrayList<String>();
for (Var var : vars) {
if(var.getName().startsWith(prefix)) {
String proposal = var.getName().substring(prefix.length());
proposals.add(proposal);
}
}
return proposals;
}
/*
* (non-Javadoc)
* @see org.jboss.tools.common.el.core.resolver.ELCompletionEngine#resolveELOperand(org.eclipse.core.resources.IFile, org.jboss.tools.common.el.core.model.ELExpression, boolean, java.util.List, org.jboss.tools.common.el.core.resolver.ElVarSearcher)
*/
public ELResolutionImpl resolveELOperand(IFile file, ELContext context,
ELExpression operand, boolean returnEqualedVariablesOnly,
List<Var> vars, ElVarSearcher varSearcher, int offset)
throws BadLocationException, StringIndexOutOfBoundsException {
if(operand == null) {
//TODO
return null;
}
String oldEl = operand.getText();
Var var = varSearcher.findVarForEl(oldEl, context, vars, true);
String suffix = ""; //$NON-NLS-1$
String newEl = oldEl;
TypeInfoCollector.MemberInfo member = null;
boolean isArray = false;
ELResolution varELResolution = null;
if(var!=null) {
varELResolution = resolveEL(file, context, var.getElToken(), true, offset);
if(varELResolution!=null && varELResolution.isResolved()) {
ELSegment segment = varELResolution.getLastSegment();
if(segment instanceof JavaMemberELSegment) {
member = ((JavaMemberELSegment)segment).getMemberInfo();
}
}
if(member!=null) {
if(!member.getType().isArray()) {
IType type = member.getMemberType();
if(type!=null) {
try {
if(TypeInfoCollector.isInstanceofType(type, "java.util.Map")) { //$NON-NLS-1$
suffix = collectionAdditionForMapDataModel;
} else if(TypeInfoCollector.isInstanceofType(type, "java.lang.Iterable")) { //$NON-NLS-1$
suffix = collectionAdditionForCollectionDataModel;
}
} catch (JavaModelException e) {
log(e);
}
}
} else {
isArray = true;
}
}
if(var.getElToken() != null) {
newEl = var.getElToken().getText() + suffix + oldEl.substring(var.getName().length());
}
}
boolean prefixWasChanged = !oldEl.equals(newEl);
if(prefixWasChanged && isArray) {
member.setDataModel(true);
}
ELExpression newOperand = (prefixWasChanged)
? ((suffix.length() > 0 && getParserFactory() == ELParserUtil.getDefaultFactory())
? parseOperand(newEl, ELParserUtil.getCollectionFactory())
: parseOperand(newEl))
: operand;
ELResolutionImpl resolution = resolveELOperand(file, context, newOperand, returnEqualedVariablesOnly, prefixWasChanged, offset);
if(resolution==null) {
return null;
}
if(prefixWasChanged) {
resolution.setSourceOperand(operand);
// Replace segment which came from var resolution to original first segment.
LexicalToken firstOriginalToken = operand.getFirstToken();
LexicalToken nextOriginalToken = firstOriginalToken;
List<ELSegment> newSegments = resolution.getSegments();
List<ELSegment> resultSegments = new ArrayList<ELSegment>();
int startSuffix = var.getElToken().getText().length();
int endSuffix = startSuffix + suffix.length();
ELSegment firstSegment = null;
boolean sufixIsNotResolved = false;
for (ELSegment segment : newSegments) {
int startPosition = segment.getToken().getStart();
if(startPosition>=endSuffix) {
resultSegments.add(segment);
nextOriginalToken = nextOriginalToken.findTokenForward(JavaNameTokenDescription.JAVA_NAME);
((ELSegmentImpl)segment).setToken(nextOriginalToken);
} else {
if(!sufixIsNotResolved) {
sufixIsNotResolved = !segment.isResolved();
}
firstSegment = segment;
((ELSegmentImpl)firstSegment).setVars(varSearcher.findVarsForEl(oldEl, context, vars, true));
((ELSegmentImpl)firstSegment).setToken(firstOriginalToken);
((ELSegmentImpl)firstSegment).setResolved(!sufixIsNotResolved);
// if(firstSegment instanceof JavaMemberELSegmentImpl) {
// JavaMemberELSegmentImpl javaSegment = (JavaMemberELSegmentImpl) firstSegment;
// MemberInfo m = javaSegment.getMemberInfo();
// if(m!=null) {
// TypeInfoCollector.Type t = m.getType();
// if(t!=null) {
// javaSegment.setElement(t.getSource());
// }
// }
// }
}
}
if(firstSegment!=null && firstSegment.isResolved()) {
resultSegments.add(0, firstSegment);
resolution.setSegments(resultSegments);
var.resolveValue("#{" + var.getElToken().getText() + suffix + "}"); //$NON-NLS-1$ //$NON-NLS-2$
// Save all used variables from "value" EL to the list of used variables for EL which uses this "var" attribute.
if(firstSegment.getVariables()!=null) {
for (ELSegment segment : varELResolution.getSegments()) {
if(segment.getVariables()!=null) {
firstSegment.getVariables().addAll(segment.getVariables());
}
}
}
ELResolutionImpl oldElResolution = resolveELOperand(file, context, operand, returnEqualedVariablesOnly, false, offset);
if(oldElResolution!=null) {
resolution.getProposals().addAll(oldElResolution.getProposals());
}
} else {
resolution = resolveELOperand(file, context, operand, returnEqualedVariablesOnly, false, offset);
if(var != null && !resolution.getSegments().isEmpty()) {
((ELSegmentImpl)resolution.getSegments().get(0)).setVars(varSearcher.findVarsForEl(oldEl, context, vars, true));
}
}
}
if(resolution==null) {
return null;
}
// JBIDE-512, JBIDE-2541 related changes ===>>>
if(!returnEqualedVariablesOnly && vars!=null) {
for (Var v : vars) {
String prefix = operand.toString();
if(v.getName().startsWith(prefix)) {
ELResolution r = resolveEL(file, context, v.getElToken(), true, vars, varSearcher, offset);
if(r==null) {
continue;
}
ELSegment lastSegment = r.getLastSegment();
JavaMemberELSegment jmSegment = null;
if(lastSegment instanceof JavaMemberELSegment) {
jmSegment = ((JavaMemberELSegment)lastSegment);
}
MemberInfo memberInfo = jmSegment == null ? null : jmSegment.getMemberInfo();
String sourceTypeName = memberInfo == null ? null : memberInfo.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1) {
sourceTypeName = Signature.getSimpleName(sourceTypeName);
}
String typeName = memberInfo == null ? null : memberInfo.getMemberTypeName();
if (typeName != null && typeName.indexOf('.') != -1) {
typeName = Signature.getSimpleName(typeName);
}
String varNameProposal = v.getName().substring(prefix.length());
ELTextProposal proposal = new ELTextProposal();
proposal.setLabel(v.getName());
proposal.setReplacementString(varNameProposal);
proposal.setLabel(v.getName());
proposal.setImageDescriptor(getELProposalImageForMember(memberInfo));
proposal.setType(typeName);
proposal.setSourceType(sourceTypeName);
if (jmSegment != null) {
IJavaElement[] javaElements = jmSegment.getAllJavaElements();
for (int jeIndex = 0; javaElements != null && jeIndex < javaElements.length; jeIndex++) {
proposal.addJavaElement(javaElements[jeIndex]);
}
}
resolution.getProposals().add(proposal);
}
}
}
// <<<=== JBIDE-512, JBIDE-2541 related changes
return resolution;
}
/**
* Returns ELResolution for EL.
* @param seamProject
* @param file
* @param operand EL without #{}
* Returns ELResolution for EL.
* @throws BadLocationException
* @throws StringIndexOutOfBoundsException
*/
public ELResolution resolveEL(IFile file, ELContext context, ELExpression operand, boolean varIsUsed, int offset) throws BadLocationException, StringIndexOutOfBoundsException {
if(!(operand instanceof ELInvocationExpression)) return null;
return resolveELOperand(file, context, operand, true, varIsUsed, offset);
}
/**
* Returns ELResolution for EL.
* @param file
* @param operand EL without #{}
* @param offset TODO
* @param seamProject
* @return ELResolution for EL.
* @throws BadLocationException
* @throws StringIndexOutOfBoundsException
*/
public ELResolution resolveEL(IFile file, ELContext context, ELExpression operand, boolean returnEqualedVariablesOnly, List<Var> vars, ElVarSearcher varSearcher, int offset) throws BadLocationException, StringIndexOutOfBoundsException {
if(!(operand instanceof ELInvocationExpression)) return null;
return resolveELOperand(file, context, operand, returnEqualedVariablesOnly, vars, varSearcher, offset);
}
public ELResolutionImpl resolveELOperand(IFile file, ELContext context, ELExpression operand,
boolean returnEqualedVariablesOnly, boolean varIsUsed, int offset) throws BadLocationException, StringIndexOutOfBoundsException {
if(!(operand instanceof ELInvocationExpression) || file == null) {
return null;
}
ELResolutionImpl resolution = new ELResolutionImpl(operand);
ELInvocationExpression expr = (ELInvocationExpression)operand;
boolean isIncomplete = expr.getType() == ELObjectType.EL_PROPERTY_INVOCATION
&& ((ELPropertyInvocation)expr).getName() == null;
boolean isArgument = expr.getType() == ELObjectType.EL_ARGUMENT_INVOCATION;
ELInvocationExpression left = expr;
List<V> resolvedVariables = EMPTY_VARIABLES_LIST;
if (expr.getLeft() != null && isArgument) {
//argument may be applied not to a variable but to a complex expression.
left = expr.getLeft();
// resolvedVariables = resolveVariables(file, left, false,
// true, offset); // is Final and equal names are because of
// // we have no more to resolve the parts of expression,
// // but we have to resolve arguments of probably a message component
} //else
if (expr.getLeft() == null && isIncomplete) {
resolvedVariables = resolveVariables(file, context, expr, true,
returnEqualedVariablesOnly, offset);
} else {
while(left != null) {
List<V> resolvedVars = resolveVariables(file, context,
left, left == expr,
returnEqualedVariablesOnly, offset);
if (resolvedVars != null && !resolvedVars.isEmpty()) {
resolvedVariables = resolvedVars;
resolution.setLastResolvedToken(left);
break;
}
left = (ELInvocationExpression)left.getLeft();
}
}
if (resolution.getLastResolvedToken() == null &&
!returnEqualedVariablesOnly &&
expr != null &&
isIncomplete) {
// no vars are resolved
// the tokens are the part of var name ended with a separator (.)
resolvedVariables = resolveVariables(file, context, expr, true, returnEqualedVariablesOnly, offset);
Set<TextProposal> proposals = new TreeSet<TextProposal>(TextProposal.KB_PROPOSAL_ORDER);
JavaMemberELSegmentImpl segment = new JavaMemberELSegmentImpl(expr.getFirstToken());
segment.setResolved(false);
resolution.addSegment(segment);
for (V var : resolvedVariables) {
String varName = var.getName();
if(varName.startsWith(operand.getText())) {
// JBIDE-512, JBIDE-2541 related changes ===>>>
MemberInfo member = getMemberInfoByVariable(var, context, true, offset);
String sourceTypeName = member == null ? null : member.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1)
sourceTypeName = Signature.getSimpleName(sourceTypeName);
String typeName = member == null ? null : member.getMemberTypeName();
if (typeName != null && typeName.indexOf('.') != -1)
typeName = Signature.getSimpleName(typeName);
IJavaElement element = member == null ? null : member.getJavaElement();
ELTextProposal proposal = new ELTextProposal();
proposal.setLabel(varName);
proposal.setReplacementString(varName.substring(operand.getLength()));
setImage(proposal, var);
proposal.setType(typeName);
proposal.setSourceType(sourceTypeName);
if (element != null) {
proposal.addJavaElement(element);
}
proposals.add(proposal);
// <<<=== JBIDE-512, JBIDE-2541 related changes
}
}
resolution.setProposals(proposals);
return resolution;
}
// Here we have a list of vars for some part of expression
// OK. we'll proceed with members of these vars
if (resolution.getLastResolvedToken() == operand) {
// First segment is the last one
Set<TextProposal> proposals = new TreeSet<TextProposal>(TextProposal.KB_PROPOSAL_ORDER);
// In some cases there may be a few references to the same variable name.
// For example @Factory and @DataModel. We should use @DataModel instead of @Factory
// method which returns null.
// See https://jira.jboss.org/jira/browse/JBIDE-3694
// JBIDE-512, JBIDE-2541 related changes ===>>>
TypeInfoCollector.MemberInfo bijectedAttribute = null;
LexicalToken t = operand.getFirstToken();
if(t != null && t != operand.getLastToken() && operand.getLastToken() != null) {
t = t.getCombinedToken(operand.getLastToken());
}
JavaMemberELSegmentImpl segment = new JavaMemberELSegmentImpl(t);
segment.setResolved(true);
resolution.addSegment(segment);
for (V var : resolvedVariables) {
if(isSingularAttribute(var)) {
bijectedAttribute = getMemberInfoByVariable(var, context, true, offset);
}
MemberInfo member = getMemberInfoByVariable(var, context, true, offset);
String sourceTypeName = member == null ? null : member.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1)
sourceTypeName = Signature.getSimpleName(sourceTypeName);
String typeName = member == null ? null : member.getMemberTypeName();
if (typeName != null && typeName.indexOf('.') != -1)
typeName = Signature.getSimpleName(typeName);
IJavaElement element = member == null ? null : member.getJavaElement();
String varName = var.getName();
if(operand.getLength()<=varName.length()) {
ELTextProposal proposal = new ELTextProposal();
proposal.setReplacementString(varName.substring(operand.getLength()));
proposal.setLabel(varName);
setImage(proposal, var);
proposal.setType(typeName);
proposal.setSourceType(sourceTypeName);
if (element != null) {
proposal.addJavaElement(element);
}
proposals.add(proposal);
} else if(returnEqualedVariablesOnly) {
ELTextProposal proposal = new ELTextProposal();
proposal.setReplacementString(varName);
proposal.setLabel(varName);
setImage(proposal, var);
proposal.setType(typeName);
proposal.setSourceType(sourceTypeName);
if (element != null) {
proposal.addJavaElement(element);
}
proposals.add(proposal);
}
if(member!=null || bijectedAttribute!=null) {
segment.setMemberInfo(bijectedAttribute!=null?bijectedAttribute:member);
}
segment.getVariables().add(var);
}
// <<<=== JBIDE-512, JBIDE-2541 related changes
resolution.setLastResolvedToken(expr);
resolution.setProposals(proposals);
return resolution;
}
// First segment is found - proceed with next tokens
List<TypeInfoCollector.MemberInfo> members = new ArrayList<TypeInfoCollector.MemberInfo>();
JavaMemberELSegmentImpl segment = new JavaMemberELSegmentImpl(expr.getFirstToken());
for (V var : resolvedVariables) {
TypeInfoCollector.MemberInfo member = getMemberInfoByVariable(var, context, returnEqualedVariablesOnly, offset);
if (member != null && !members.contains(member)) {
String name = var.getName();
if(name.indexOf('.') >= 0) {
LexicalToken last = expr.getFirstToken();
StringBuffer sb = new StringBuffer();
sb.append(last.getText());
while(!name.equals(sb.toString()) && last != null) {
last = last.getNextToken();
if(last != null) {
sb.append(last.getText());
}
}
if(last != null && name.equals(sb.toString())) {
segment = new JavaMemberELSegmentImpl(expr.getFirstToken().getCombinedToken(last));
}
}
members.add(member);
segment.setMemberInfo(member);
segment.getVariables().add(var);
segment.setResolved(true);
}
}
resolution.addSegment(segment);
//process segments one by one
if(left != null) {
while(left != expr) {
left = (ELInvocationExpression)left.getParent();
if (left != expr) { // inside expression
JavaMemberELSegmentImpl lastSegment = segment;
segment = new JavaMemberELSegmentImpl(left.getLastToken());
boolean skipSegment = false;
// The segment could have a collection or a map data model (or probably both?)
MemberInfo lastSegmentMemberInfo = lastSegment == null ? null : lastSegment.getMemberInfo();
boolean isMap = false;
boolean isCollection = false;
if (lastSegmentMemberInfo != null) {
if(!lastSegmentMemberInfo.getType().isArray()) {
IType type = lastSegmentMemberInfo.getMemberType();
try {
if(TypeInfoCollector.isInstanceofType(type, "java.util.Map")) { //$NON-NLS-1$
isMap = true;
} else if(TypeInfoCollector.isInstanceofType(type, "java.lang.Iterable")) { //$NON-NLS-1$
isCollection = true;
}
} catch (JavaModelException e) {
log(e);
}
}
}
if(left instanceof ELArgumentInvocation ||
(left instanceof ELPropertyInvocation && !(left instanceof ELMethodInvocation) && (isMap || isCollection))
) {
List<MemberInfo> ms = new ArrayList<MemberInfo>(members);
members.clear();
if(isMap) {
skipSegment = true;
String s = "#{" + left.getLeft().toString() + ".values().iterator().next()}"; //$NON-NLS-1$ //$NON-NLS-2$
if(getParserFactory()!=null) {
ELParser p = getParserFactory().createParser();
ELInvocationExpression expr1 = (ELInvocationExpression)p.parse(s).getInstances().get(0).getExpression();
members = resolveSegment(expr1.getLeft().getLeft(), ms, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
members = resolveSegment(expr1.getLeft(), members, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
members = resolveSegment(expr1, members, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
if(resolution.getLastResolvedToken() == expr1) {
resolution.setLastResolvedToken(left);
}
}
segment = lastSegment;
} else if(isCollection) {
skipSegment = true;
String s = "#{" + left.getLeft().toString() + collectionAdditionForCollectionDataModel + "}"; //$NON-NLS-1$ //$NON-NLS-2$
if(getParserFactory()!=null) {
ELParser p = getParserFactory().createParser();
ELInvocationExpression expr1 = (ELInvocationExpression)p.parse(s).getInstances().get(0).getExpression();
members = resolveSegment(expr1.getLeft(), ms, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
members = resolveSegment(expr1, members, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
if(resolution.getLastResolvedToken() == expr1) {
resolution.setLastResolvedToken(left);
}
}
segment = lastSegment;
}
/*
String s = "#{" + left.getLeft().toString() + collectionAdditionForCollectionDataModel + "}"; //$NON-NLS-1$ //$NON-NLS-2$
if(getParserFactory()!=null) {
ELParser p = getParserFactory().createParser();
ELInvocationExpression expr1 = (ELInvocationExpression)p.parse(s).getInstances().get(0).getExpression();
members = resolveSegment(expr1.getLeft(), members, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
members = resolveSegment(expr1, members, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
if(resolution.getLastResolvedToken() == expr1) {
resolution.setLastResolvedToken(left);
}
}
*/
if(members.isEmpty()) {
members = resolveSegment(left, ms, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
}
} else {
members = resolveSegment(left, members, resolution, returnEqualedVariablesOnly, varIsUsed, segment);
}
if(!skipSegment) { // Do not store any members if the segment is 'skipped' because it's already resolved.
if (!members.isEmpty()) {
segment.setResolved(true);
segment.setMemberInfo(members.get(0)); // TODO: This is a buggy way to select a member to setup in a segment
}
resolution.addSegment(segment);
}
} else { // Last segment
resolveLastSegment((ELInvocationExpression)operand, members, resolution, returnEqualedVariablesOnly, varIsUsed);
break;
}
}
}
if(resolution.getProposals().isEmpty() && !resolution.getSegments().isEmpty()) {
// && status.getUnpairedGettersOrSetters()!=null) {
ELSegment lastSegment = resolution.getSegments().get(resolution.getSegments().size()-1);
if(lastSegment instanceof JavaMemberELSegmentImpl) {
((JavaMemberELSegmentImpl)lastSegment).clearUnpairedGettersOrSetters();
}
}
return resolution;
}
abstract public List<V> resolveVariables(IFile file, ELContext context, ELInvocationExpression expr, boolean isFinal, boolean onlyEqualNames, int offset);
abstract protected TypeInfoCollector.MemberInfo getMemberInfoByVariable(V var, ELContext context, boolean onlyEqualNames, int offset);
abstract protected boolean isStaticMethodsCollectingEnabled();
protected boolean isSingularAttribute(V var) {
return false;
}
protected List<TypeInfoCollector.MemberInfo> resolveSegment(ELInvocationExpression expr,
List<TypeInfoCollector.MemberInfo> members,
ELResolutionImpl resolution,
boolean returnEqualedVariablesOnly, boolean varIsUsed, JavaMemberELSegmentImpl segment) {
LexicalToken lt = (expr instanceof ELPropertyInvocation)
? ((ELPropertyInvocation)expr).getName()
: (expr instanceof ELMethodInvocation)
? ((ELMethodInvocation)expr).getName()
: (expr instanceof ELArgumentInvocation && ((ELArgumentInvocation)expr).getArgument().getArgument() != null)
? ((ELArgumentInvocation)expr).getArgument().getArgument().getFirstToken()
: null;
String name = lt != null ? lt.getText() : ""; // token.getText(); //$NON-NLS-1$
if(expr instanceof ELArgumentInvocation) {
if(name.startsWith("'")) name = name.substring(1); else name = ""; //$NON-NLS-1$ //$NON-NLS-2$
if(name.endsWith("'")) name = name.substring(0, name.length() - 1); else name = ""; //$NON-NLS-1$ //$NON-NLS-2$
}
segment.setToken(lt);
if (expr.getType() == ELObjectType.EL_PROPERTY_INVOCATION || expr.getType() == ELObjectType.EL_ARGUMENT_INVOCATION) {
// Find properties for the token
List<TypeInfoCollector.MemberInfo> newMembers = new ArrayList<TypeInfoCollector.MemberInfo>();
for (TypeInfoCollector.MemberInfo mbr : members) {
if (mbr.getMemberType() == null) continue;
ICompilationUnit unit = mbr.getMemberType().getCompilationUnit();
if(unit!=null && unit.exists()) {
IResource resource;
try {
resource = unit.getCorrespondingResource();
if(resource!=null) {
segment.setResource(resource);
}
} catch (JavaModelException e) {
ELCorePlugin.getDefault().logError(e);
}
}
TypeInfoCollector infos = mbr.getTypeCollector(varIsUsed, isStaticMethodsCollectingEnabled());
if (TypeInfoCollector.isNotParameterizedCollection(mbr) || TypeInfoCollector.isResourceBundle(mbr.getMemberType())) {
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
}
List<TypeInfoCollector.MemberInfo> properties = infos.getProperties();
for (TypeInfoCollector.MemberInfo property : properties) {
String propertyName = property.getName();
if (property instanceof TypeInfoCollector.MethodInfo) { // Setter or getter
propertyName = BeanUtil.getPropertyName(propertyName);
}
if (name.equals(propertyName.toString())) {
newMembers.add(property);
}
}
}
members = newMembers;
if (members != null && !members.isEmpty())
resolution.setLastResolvedToken(expr);
}
if (expr.getType() == ELObjectType.EL_METHOD_INVOCATION) {
// Find methods for the token
if (name.indexOf('(') != -1) {
name = name.substring(0, name.indexOf('('));
}
List<TypeInfoCollector.MemberInfo> newMembers = new ArrayList<TypeInfoCollector.MemberInfo>();
for (TypeInfoCollector.MemberInfo mbr : members) {
if (mbr.getMemberType() == null) continue;
//Fix for JBIDE-21374: varIsUsed instead of false
TypeInfoCollector infos = mbr.getTypeCollector(varIsUsed, isStaticMethodsCollectingEnabled());
if (TypeInfoCollector.isNotParameterizedCollection(mbr) || TypeInfoCollector.isResourceBundle(mbr.getMemberType())) {
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
}
List<TypeInfoCollector.MemberInfo> methods = infos.getMethods();
for (TypeInfoCollector.MemberInfo method : methods) {
if (name.equals(method.getName())) {
newMembers.add(method);
}
}
}
members = newMembers;
if (members != null && !members.isEmpty())
resolution.setLastResolvedToken(expr);
}
return members;
}
protected void resolveLastSegment(ELInvocationExpression expr,
List<TypeInfoCollector.MemberInfo> members,
ELResolutionImpl resolution,
boolean returnEqualedVariablesOnly, boolean varIsUsed) {
Set<TextProposal> kbProposals = new TreeSet<TextProposal>(TextProposal.KB_PROPOSAL_ORDER);
JavaMemberELSegmentImpl segment = new JavaMemberELSegmentImpl(null);
if(expr instanceof ELPropertyInvocation) {
segment.setToken(((ELPropertyInvocation)expr).getName());
}
if(segment.getToken()!=null) {
resolution.addSegment(segment);
} else {
segment.setToken(expr.getLastToken());
}
resolution.setProposals(kbProposals);
if (expr.getType() == ELObjectType.EL_PROPERTY_INVOCATION && ((ELPropertyInvocation)expr).getName() == null) {
// return all the methods + properties
for (TypeInfoCollector.MemberInfo mbr : members) {
if(isSingularMember(mbr)) {
processSingularMember(mbr, kbProposals);
continue;
}
if (mbr.getMemberType() == null) {
continue;
}
try {
if(TypeInfoCollector.isInstanceofType(mbr.getMemberType(), "java.util.Map")) { //$NON-NLS-1$
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
//if map/collection is parameterized, we might return member info for value type.
return;
}
} catch (JavaModelException jme) {
ELCorePlugin.getDefault().logError(jme);
}
TypeInfoCollector infos = mbr.getTypeCollector(varIsUsed, isStaticMethodsCollectingEnabled());
if (TypeInfoCollector.isNotParameterizedCollection(mbr) || TypeInfoCollector.isResourceBundle(mbr.getMemberType())) {
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
}
// JBIDE-512, JBIDE-2541 related changes ===>>>
/*
Set<String> methodPresentations =
infos.getMethodPresentationStrings();
if (methodPresentations != null) {
for (String presentation : methodPresentations) {
TextProposal proposal = new TextProposal();
proposal.setReplacementString(presentation);
proposal.setImage(getELProposalImage());
kbProposals.add(proposal);
}
}
*/
Set<MemberPresentation> methodPresentations =
infos.getMethodPresentations(returnEqualedVariablesOnly);
if (methodPresentations != null) {
for (MemberPresentation presentation : methodPresentations) {
String presentationString = presentation.getPresentation();
String presentationDisplayName = presentation.getPresentationDisplayName();
MemberInfo member = presentation.getMember();
String sourceTypeName = member == null ? null : member.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1)
sourceTypeName = Signature.getSimpleName(sourceTypeName);
String typeName = member == null ? null : member.getMemberTypeName();
if (typeName != null && typeName.indexOf('.') != -1)
typeName = Signature.getSimpleName(typeName);
ELTextProposal proposal = new ELTextProposal();
proposal.setReplacementString(presentationString);
proposal.setLabel(presentationDisplayName);
proposal.setImageDescriptor(getELProposalImage(presentation));
proposal.setType(typeName);
proposal.setSourceType(sourceTypeName);
for (MemberInfo mi : presentation.getAllMembers()) {
IJavaElement element = mi.getJavaElement();
if (element != null) {
proposal.addJavaElement(element);
}
}
kbProposals.add(proposal);
}
}
/*
Set<String> propertyPresentations =
infos.getPropertyPresentationStrings(status.getUnpairedGettersOrSetters());
if (propertyPresentations != null) {
for (String presentation : propertyPresentations) {
TextProposal proposal = new TextProposal();
proposal.setReplacementString(presentation);
proposal.setImage(getELProposalImage());
kbProposals.add(proposal);
}
}
*/
Set<MemberPresentation> propertyPresentations =
infos.getPropertyPresentations(segment.getUnpairedGettersOrSetters(), returnEqualedVariablesOnly);
if (propertyPresentations != null) {
for (MemberPresentation presentation : propertyPresentations) {
String presentationString = presentation.getPresentation();
String presentationDisplayName = presentation.getPresentationDisplayName();
MemberInfo member = presentation.getMember();
String sourceTypeName = member == null ? null : member.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1)
sourceTypeName = Signature.getSimpleName(sourceTypeName);
String typeName = member == null ? null : member.getMemberTypeName();
if (typeName != null && typeName.indexOf('.') != -1)
typeName = Signature.getSimpleName(typeName);
ELTextProposal proposal = new ELTextProposal();
proposal.setReplacementString(presentationString);
proposal.setLabel(presentationDisplayName);
proposal.setImageDescriptor(getELProposalImage(presentation));
proposal.setType(typeName);
proposal.setSourceType(sourceTypeName);
for (MemberInfo mi : presentation.getAllMembers()) {
IJavaElement element = mi.getJavaElement();
if (element != null) {
proposal.addJavaElement(element);
}
}
kbProposals.add(proposal);
}
}
// <<<=== JBIDE-512, JBIDE-2541 related changes
}
} else
if(expr.getType() != ELObjectType.EL_ARGUMENT_INVOCATION)
//actually any case
// if (token.getType() == ELOperandToken.EL_VARIABLE_NAME_TOKEN ||
// token.getType() == ELOperandToken.EL_PROPERTY_NAME_TOKEN ||
// token.getType() == ELOperandToken.EL_METHOD_TOKEN)
{
// return filtered methods + properties
Set<TypeInfoCollector.MemberPresentation> proposalsToFilter = new TreeSet<TypeInfoCollector.MemberPresentation>(TypeInfoCollector.MEMBER_PRESENTATION_COMPARATOR);
for (TypeInfoCollector.MemberInfo mbr : members) {
if(isSingularMember(mbr)) {
filterSingularMember(mbr, proposalsToFilter);
continue;
}
if (mbr.getMemberType() == null) continue;
try {
if(TypeInfoCollector.isInstanceofType(mbr.getMemberType(), "java.util.Map")) { //$NON-NLS-1$
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
segment.setResolved(true);
//if map/collection is parameterized, we might return member info for value type.
return;
}
} catch (JavaModelException jme) {
ELCorePlugin.getDefault().logError(jme);
}
TypeInfoCollector infos = mbr.getTypeCollector(false, isStaticMethodsCollectingEnabled());
if (TypeInfoCollector.isNotParameterizedCollection(mbr) || TypeInfoCollector.isResourceBundle(mbr.getMemberType())) {
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
}
proposalsToFilter.addAll(infos.getMethodPresentations(returnEqualedVariablesOnly));
proposalsToFilter.addAll(infos.getPropertyPresentations(segment.getUnpairedGettersOrSetters(), returnEqualedVariablesOnly));
// segment.setMemberInfo(mbr);
}
for (TypeInfoCollector.MemberPresentation proposal : proposalsToFilter) {
// We do expect nothing but name for method tokens (No round brackets)
String filter = expr.getMemberName();
if(filter == null) filter = ""; //$NON-NLS-1$
String presentationString = proposal.getPresentation();
//proposal.getMember().getSourceType().getCompilationUnit().getCorrespondingResource()
MemberInfo info = proposal.getMember();
if(info!=null) {
IType type = info.getSourceType();
if(type!=null) {
ICompilationUnit unit = type.getCompilationUnit();
if(unit!=null && unit.exists()) {
try {
IResource resource = unit.getCorrespondingResource();
if(resource!=null) {
segment.setResource(resource);
}
} catch (JavaModelException e) {
ELCorePlugin.getDefault().logError(e);
}
}
}
}
if(returnEqualedVariablesOnly) {
// This is used for validation.
if (presentationString.equals(filter)) {
TextProposal kbProposal = new TextProposal();
kbProposal.setReplacementString(proposal.getPresentation());
setImage(kbProposal, proposal);
kbProposals.add(kbProposal);
segment.setMemberInfo(proposal.getMember());
if (proposal.getAllMembers() != null && !proposal.getAllMembers().isEmpty()) {
for (MemberInfo mi : proposal.getAllMembers()) {
IJavaElement je = mi.getJavaElement();
if (je != null) {
segment.addJavaElement(je);
}
}
}
if(segment.getUnpairedGettersOrSetters()!=null) {
TypeInfoCollector.MethodInfo unpirMethod = segment.getUnpairedGettersOrSetters().get(filter);
segment.clearUnpairedGettersOrSetters();
if(unpirMethod!=null) {
segment.getUnpairedGettersOrSetters().put(filter, unpirMethod);
}
}
break;
}
} else if (presentationString.startsWith(filter)) {
// JBIDE-512, JBIDE-2541 related changes ===>>>
// This is used for CA.
MemberInfo member = proposal.getMember();
String sourceTypeName = member == null ? null : member.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1)
sourceTypeName = Signature.getSimpleName(sourceTypeName);
String typeName = member == null ? null : member.getMemberTypeName();
if (typeName != null && typeName.indexOf('.') != -1)
typeName = Signature.getSimpleName(typeName);
ELTextProposal kbProposal = new ELTextProposal();
kbProposal.setReplacementString(proposal.getPresentation().substring(filter.length()));
kbProposal.setLabel(proposal.getPresentationDisplayName());
kbProposal.setImageDescriptor(getELProposalImageForMember(proposal.getMember()));
kbProposal.setType(typeName);
kbProposal.setSourceType(sourceTypeName);
for (MemberInfo mi : proposal.getAllMembers()) {
IJavaElement element = mi.getJavaElement();
if (element != null) {
kbProposal.addJavaElement(element);
}
}
kbProposals.add(kbProposal);
// <<<=== JBIDE-512, JBIDE-2541 related changes
}
}
} else if(expr.getType() == ELObjectType.EL_ARGUMENT_INVOCATION) {
Set<TypeInfoCollector.MemberPresentation> proposalsToFilter = new TreeSet<TypeInfoCollector.MemberPresentation>(TypeInfoCollector.MEMBER_PRESENTATION_COMPARATOR);
boolean isMessages = false;
for (TypeInfoCollector.MemberInfo mbr : members) {
if(isSingularMember(mbr)) {
isMessages = true;
filterSingularMember(mbr, proposalsToFilter);
continue;
}
if (mbr.getMemberType() == null) continue;
try {
if(TypeInfoCollector.isInstanceofType(mbr.getMemberType(), "java.util.Map")) { //$NON-NLS-1$
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
//if map/collection is parameterized, we might return member info for value type.
return;
}
} catch (JavaModelException jme) {
ELCorePlugin.getDefault().logError(jme);
}
//Try properties if argument is a string.
TypeInfoCollector infos = mbr.getTypeCollector(false, isStaticMethodsCollectingEnabled());
if (TypeInfoCollector.isNotParameterizedCollection(mbr) || TypeInfoCollector.isResourceBundle(mbr.getMemberType())) {
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
}
proposalsToFilter.addAll(infos.getPropertyPresentations(segment.getUnpairedGettersOrSetters(), returnEqualedVariablesOnly));
if(!proposalsToFilter.isEmpty()) {
resolution.addSegment(segment);
if(expr instanceof ELArgumentInvocation) {
ELArgument a = ((ELArgumentInvocation)expr).getArgument();
if(a.getArgument() == null) {
segment.setToken(((ELObject)a).getFirstToken());
} else {
segment.setToken(a.getArgument().getFirstToken());
}
}
}
segment.setMemberInfo(mbr);
}
String filter = expr.getMemberName();
boolean bSurroundWithQuotes = false;
boolean closeQuotes = false;
if(filter == null) {
filter = ""; //$NON-NLS-1$
bSurroundWithQuotes = true;
} else {
if((filter.startsWith("'") || filter.startsWith("\"")) //$NON-NLS-1$ //$NON-NLS-2$
|| (filter.endsWith("'") || filter.endsWith("\""))) { //$NON-NLS-1$ //$NON-NLS-2$
if (filter.startsWith("'") || filter.startsWith("\"")) { //$NON-NLS-1$ //$NON-NLS-2$
filter = filter.length() == 1 ? "" : filter.substring(1); //$NON-NLS-1$
closeQuotes = true;
}
if (filter.endsWith("'") || filter.endsWith("\"")) { //$NON-NLS-1$ //$NON-NLS-2$
filter = filter.length() == 1 ? "" : filter.substring(0, filter.length() - 1); //$NON-NLS-1$
closeQuotes = false;
}
} else if(isInteger(filter)) {
segment.setValidatable(false);
return;
} else {
//Value is set as expression itself, we cannot compute it
if(isMessages) {
resolution.setMapOrCollectionOrBundleAmoungTheTokens(true);
}
return;
}
}
for (TypeInfoCollector.MemberPresentation proposal : proposalsToFilter) {
if(returnEqualedVariablesOnly) {
// This is used for validation.
if (proposal.getPresentation().equals(filter)) {
TextProposal kbProposal = new TextProposal();
kbProposal.setReplacementString(proposal.getPresentation());
setImage(kbProposal, proposal);
kbProposals.add(kbProposal);
segment.setMemberInfo(proposal.getMember());
if (proposal.getAllMembers() != null && !proposal.getAllMembers().isEmpty()) {
for (MemberInfo mi : proposal.getAllMembers()) {
IJavaElement je = mi.getJavaElement();
if (je != null) {
segment.addJavaElement(je);
}
}
}
if(segment.getUnpairedGettersOrSetters()!=null) {
TypeInfoCollector.MethodInfo unpirMethod = segment.getUnpairedGettersOrSetters().get(filter);
segment.clearUnpairedGettersOrSetters();
if(unpirMethod!=null) {
segment.getUnpairedGettersOrSetters().put(filter, unpirMethod);
}
}
break;
}
} else if (proposal.getPresentation().startsWith(filter)) {
// This is used for CA.
// JBIDE-512, JBIDE-2541 related changes ===>>>
MemberInfo member = proposal.getMember();
String sourceTypeName = member == null ? null : member.getDeclaringTypeQualifiedName();
if (sourceTypeName != null && sourceTypeName.indexOf('.') != -1)
sourceTypeName = Signature.getSimpleName(sourceTypeName);
String typeName = member == null ? null : member.getType().getName();
if (typeName != null && typeName.indexOf('.') != -1)
typeName = Signature.getSimpleName(typeName);
ELTextProposal kbProposal = new ELTextProposal();
String replacementString = proposal.getPresentation().substring(filter.length());
if (bSurroundWithQuotes) {
replacementString = "'" + replacementString + "'"; //$NON-NLS-1$ //$NON-NLS-2$
} else if(closeQuotes) {
replacementString = replacementString + "'"; //$NON-NLS-1$
}
kbProposal.setReplacementString(replacementString);
kbProposal.setLabel(proposal.getPresentationDisplayName());
kbProposal.setImageDescriptor(getELProposalImageForMember(member));
kbProposal.setType(typeName);
kbProposal.setSourceType(sourceTypeName);
for (MemberInfo mi : proposal.getAllMembers()) {
IJavaElement element = mi.getJavaElement();
if (element != null) {
kbProposal.addJavaElement(element);
}
}
kbProposals.add(kbProposal);
// <<<=== JBIDE-512, JBIDE-2541 related changes
}
}
}
segment.setResolved(!resolution.getProposals().isEmpty());
segment.setValidatable(!resolution.isMapOrCollectionOrBundleAmoungTheTokens());
}
public static boolean isInteger(String str) {
int length = str.length();
if (length == 0) {
return false;
}
int i = 0;
if (str.charAt(0) == '-') {
if (length == 1) {
return false;
}
i = 1;
}
for (; i < length; i++) {
char c = str.charAt(i);
if (c <= '/' || c >= ':') {
return false;
}
}
return true;
}
protected boolean isSingularMember(TypeInfoCollector.MemberInfo mbr) {
return false;
}
protected void processSingularMember(TypeInfoCollector.MemberInfo mbr, Set<TextProposal> kbProposals) {
}
protected void filterSingularMember(TypeInfoCollector.MemberInfo mbr, Set<TypeInfoCollector.MemberPresentation> proposalsToFilter) {
}
protected void setImage(TextProposal kbProposal, TypeInfoCollector.MemberPresentation proposal) {
kbProposal.setImageDescriptor(getELProposalImage(proposal));
}
protected void setImage(TextProposal kbProposal, V var) {
kbProposal.setImageDescriptor(getELProposalImageForMember(null));
}
/**
*
* @param document
* @param offset
* @param start start of relevant region in document
* @param end end of relevant region in document
* @return
*/
public static ELInvocationExpression findExpressionAtOffset(IDocument document, int offset, int start, int end) {
return findExpressionAtOffset(document.get(), offset, start, end);
}
public static ELInvocationExpression findExpressionAtOffset(String content, int offset, int start, int end) {
//TODO this naive calculations should be removed;
// this method should be called with reasonable start and end.
if(start <= 0) start = guessStart(content, offset);
if(end >= content.length()) end = guessEnd(content, offset);
ELParser parser = defaultFactory.createParser();
ELModel model = parser.parse(content, start, end - start);
return ELUtil.findExpression(model, offset);
}
static int guessStart(String content, int offset) {
if(offset > content.length()) offset = content.length();
if(offset < 2) return 0;
int s = offset - 2;
while(s >= 0) {
if(content.charAt(s + 1) == '{') {
char ch = content.charAt(s);
if(ch == '#' || ch == '$') return s;
}
s--;
}
return 0;
}
static int guessEnd(String content, int offset) {
if(offset >= content.length()) return content.length();
while(offset < content.length()) {
if(content.charAt(offset) == '}') return offset;
offset++;
}
return content.length();
}
/**
* Removes duplicates of completion strings
*
* @param suggestions a list of suggestions ({@link String}).
* @return a list of unique completion suggestions.
*/
public static List<TextProposal> makeProposalsUnique(List<TextProposal> suggestions) {
HashSet<String> present = new HashSet<String>();
ArrayList<TextProposal> unique= new ArrayList<TextProposal>();
if (suggestions == null)
return unique;
for (TextProposal item : suggestions) {
if (!present.contains(item.getReplacementString())) {
present.add(item.getReplacementString());
unique.add(item);
}
}
present.clear();
return unique;
}
public static LexicalToken combineLexicalTokensForExpression(ELInvocationExpression expr) {
// Create a combined lexical token to store all the variable name (not only the name before first dot, but all the name including all the words and dots)
int variableTokenType = expr.getFirstToken().getType();
int variableTokenStart = expr.getFirstToken().getStart();
int variableTokenLength = 0;
StringBuffer variableTokenText = new StringBuffer();
LexicalToken current = expr.getFirstToken();
LexicalToken variableTokenNext = null;
while (current != null && current != expr.getLastToken()) {
variableTokenText.append(current.getText());
variableTokenLength += current.getLength();
variableTokenNext = current.getNextToken();
current = variableTokenNext;
}
if (current != null) {
variableTokenText.append(current.getText());
variableTokenLength += current.getLength();
variableTokenNext = current.getNextToken();
}
LexicalToken variableToken = new LexicalToken(variableTokenStart, variableTokenLength, variableTokenText, variableTokenType);
variableToken.setNextToken(variableTokenNext);
return variableToken;
}
}