Download
Getting Started
Members
Projects
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
More
Community
Marketplace
Events
Planet Eclipse
Newsletter
Videos
Participate
Report a Bug
Forums
Mailing Lists
Wiki
IRC
How to Contribute
Working Groups
Automotive
Internet of Things
LocationTech
Long-Term Support
PolarSys
Science
OpenMDM
Toggle navigation
Bugzilla – Attachment 83328 Details for
Bug 199853
ContentAssist: Improve parent symbol resolution
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
Log In
[x]
|
Terms of Use
|
Copyright Agent
[patch]
updated version, handles someList[-1] correctly
content-assist_patch.txt (text/plain), 134.57 KB, created by
Matthias Fuessel
on 2007-11-20 09:13:11 EST
(
hide
)
Description:
updated version, handles someList[-1] correctly
Filename:
MIME Type:
Creator:
Matthias Fuessel
Created:
2007-11-20 09:13:11 EST
Size:
134.57 KB
patch
obsolete
>### Eclipse Workspace Patch 1.0 >#P org.eclipse.jst.jsf.ui >Index: src/org/eclipse/jst/jsf/ui/internal/contentassist/el/JSFELContentAssistProcessor.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.ui/src/org/eclipse/jst/jsf/ui/internal/contentassist/el/JSFELContentAssistProcessor.java,v >retrieving revision 1.3 >diff -u -r1.3 JSFELContentAssistProcessor.java >--- src/org/eclipse/jst/jsf/ui/internal/contentassist/el/JSFELContentAssistProcessor.java 4 May 2007 19:14:51 -0000 1.3 >+++ src/org/eclipse/jst/jsf/ui/internal/contentassist/el/JSFELContentAssistProcessor.java 19 Nov 2007 23:11:00 -0000 >@@ -96,11 +96,15 @@ > } > > >- final ContentAssistStrategy strategy = >- ContentAssistParser.getPrefix(documentPosition - resolver.getStartOffset() + 1, elText); >- >- if (strategy != null) >- proposals.addAll(strategy.getProposals(context)); >+ if (elText != null) { >+ IStructuredDocumentContext elRegionContext = >+ IStructuredDocumentContextFactory.INSTANCE.getContext(viewer, resolver.getStartOffset());; >+ final ContentAssistStrategy strategy = >+ ContentAssistParser.getContentAssistStrategy(elRegionContext, elText, documentPosition); >+ >+ if (strategy != null) >+ proposals.addAll(strategy.getProposals(context)); >+ } > } > } > } >#P org.eclipse.jst.jsf.core >Index: src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistStrategy.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistStrategy.java,v >retrieving revision 1.2 >diff -u -r1.2 ContentAssistStrategy.java >--- src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistStrategy.java 16 Apr 2007 19:53:23 -0000 1.2 >+++ src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistStrategy.java 19 Nov 2007 23:11:01 -0000 >@@ -38,19 +38,16 @@ > public final static int PREFIX_TYPE_EMPTY_EXPRESSION = 2; > > private final int type; >- private final String value; > private final String proposalStart; > > /** > * @param type >- * @param value > * @param proposalStart > */ >- public ContentAssistStrategy(final int type, final String value, final String proposalStart) >+ public ContentAssistStrategy(final int type, final String proposalStart) > { > super(); > this.type = type; >- this.value = value; > this.proposalStart = proposalStart; > } > >@@ -63,14 +60,6 @@ > return type; > } > >- /** >- * @return the token which this prefix is for >- */ >- public final String getValue() >- { >- return value; >- } >- > /** > * @param context > * @return the list of proposals for this strategy. Contents of the list >Index: src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistParser.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistParser.java,v >retrieving revision 1.1 >diff -u -r1.1 ContentAssistParser.java >--- src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistParser.java 28 Nov 2006 20:22:23 -0000 1.1 >+++ src/org/eclipse/jst/jsf/core/internal/contentassist/el/ContentAssistParser.java 19 Nov 2007 23:11:01 -0000 >@@ -12,26 +12,13 @@ > > package org.eclipse.jst.jsf.core.internal.contentassist.el; > >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTAddExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTAndExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTChoiceExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTEqualityExpression; >+import org.eclipse.jface.text.Region; >+import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; >+import org.eclipse.jst.jsf.context.symbol.ISymbol; >+import org.eclipse.jst.jsf.validation.internal.el.ASTResolver; > import org.eclipse.jst.jsp.core.internal.java.jspel.ASTExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTFunctionInvocation; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTLiteral; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTMultiplyExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTOrExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTRelationalExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTUnaryExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValue; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValuePrefix; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValueSuffix; > import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParser; >-import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParserConstants; >-import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParserVisitor; > import org.eclipse.jst.jsp.core.internal.java.jspel.ParseException; >-import org.eclipse.jst.jsp.core.internal.java.jspel.SimpleNode; >-import org.eclipse.jst.jsp.core.internal.java.jspel.Token; > > /** > * Consumes an EL expression and converts into a completion prefix >@@ -42,265 +29,84 @@ > public final class ContentAssistParser > { > /** >- * @param relativePosition -- 1-based position in elText (first position is 1) >+ * @param context > * @param elText >+ * @param documentPosition -- position in document > * @return a content assist strategy for the given position and el expression >- * or null if one cannot be determined > */ >- public static ContentAssistStrategy getPrefix(final int relativePosition, final String elText) >+ public static ContentAssistStrategy getContentAssistStrategy(final IStructuredDocumentContext context, final String elText, final int documentPosition) > { >- if (elText == null) >+ if (elText == null || elText.trim().length() == 0) > { >- return null; >- } >- else if ("".equals(elText.trim())) >- { >- return new IdCompletionStrategy("", ""); >- } >- >- final java.io.StringReader reader = new java.io.StringReader(elText); >- final JSPELParser parser = new JSPELParser(reader); >- >- try >- { >- final ASTExpression expr = parser.Expression(); >- final PrefixVisitor visitor = new PrefixVisitor(relativePosition, elText); >- expr.jjtAccept(visitor, null); >- return visitor.getPrefix(); >+ return new IdCompletionStrategy(""); //$NON-NLS-1$ > } >- catch (ParseException pe) >- { >- // TODO: handle parser by using current and expected tokens >+ ASTResolver astResolver = createASTResolver(context, elText); >+ if (astResolver != null) { >+ if (astResolver.findSymbolAtPos(documentPosition)) { >+ ISymbol parentSymbol = astResolver.getParentSymbol(); >+ int startPos = astResolver.getCurrentSymbolStartpos(); >+ String proposalStart = ""; //$NON-NLS-1$ >+ if (startPos >= 0 && documentPosition > startPos) { >+ int elStartPos = context.getDocumentPosition(); >+ proposalStart = elText.substring(startPos - elStartPos, documentPosition - elStartPos); >+ } >+ if (parentSymbol == null) { >+ return new IdCompletionStrategy(proposalStart); >+ } >+ if (proposalStart.equals(astResolver.getCurrentSuffixOperator())) { >+ /* if there is no identifier following the suffix operator, ASTResolver will return >+ * the suffix operator itself instead of empty string. Don't want to change this there >+ * because the same info is used for flagging errors in ASTValidator. */ >+ proposalStart = ""; //$NON-NLS-1$ >+ } >+ return new FunctionCompletionStrategy(parentSymbol, proposalStart); >+ } >+ if (astResolver.getCurrentSuffixOperator() == null) { >+ return new IdCompletionStrategy(""); //$NON-NLS-1$ >+ } > } >- > return null; > } > >- private static class PrefixVisitor implements JSPELParserVisitor >- { >- private final int _relativePos; >- private final String _fullText; >- >- private String _curPrefix; // = null; initialized as tree is visited >- private int _prefixType; >- private boolean _prefixResolved; // = false; set to true when the prefix is resolved >- private String _proposalStart = ""; >- >- PrefixVisitor(final int relativePos, final String fullText) >- { >- _relativePos = relativePos; >- _fullText = fullText; >- } >- >- /** >- * @return the prefix if resolved or null if not resolved >- */ >- public ContentAssistStrategy getPrefix() >- { >- if (_prefixResolved) >- { >- switch(_prefixType) >- { >- case ContentAssistStrategy.PREFIX_TYPE_DOT_COMPLETION: >- return new FunctionCompletionStrategy(_curPrefix, _proposalStart); >- >- case ContentAssistStrategy.PREFIX_TYPE_ID_COMPLETION: >- return new IdCompletionStrategy(_curPrefix, _proposalStart); >- >- case ContentAssistStrategy.PREFIX_TYPE_EMPTY_EXPRESSION: >- return new IdCompletionStrategy("", _proposalStart); >- >- default: >- // do nothing; fall-through to return null >- } >- } >- >- return null; >- } >- >- public Object visit(ASTAddExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTAndExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTChoiceExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTEqualityExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTFunctionInvocation node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTLiteral node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTMultiplyExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTOrExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTRelationalExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTUnaryExpression node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTValue node, Object data) >+ /** >+ * Get symbol and symbol region at given position in el string >+ * @param context - IStructuredDocumentContext >+ * @param relativePosition - position in el string >+ * @param elText - el string >+ * @return SymbolInfo. May be null. >+ */ >+ public static SymbolInfo getSymbolInfo(IStructuredDocumentContext context, final int relativePosition, final String elText) { >+ if (elText == null || elText.trim().length() == 0) > { >- // we're only in this value expr if it contains the cursor >- if (testContainsCursor(node)) >- { >- return node.childrenAccept(this, data); >- } >- > return null; > } > >- public Object visit(ASTValuePrefix node, Object data) >- { >- // for now, only concern ourselves with simple (identifier) prefixes >- if (!_prefixResolved >- && node.jjtGetNumChildren() == 0 >- && node.getFirstToken().kind == JSPELParserConstants.IDENTIFIER) >- { >- _curPrefix = node.getFirstToken().image; >- >- if (testContainsCursor(node)) >- { >- // if the cursor is on this id, we don't need to visit >- // further since we know both the prefix -- the id -- and >- // the type -- it's an id completion >- _prefixType = ContentAssistStrategy.PREFIX_TYPE_ID_COMPLETION; >- int proposalLength = _relativePos - node.getFirstToken().beginColumn; >- _proposalStart = node.getFirstToken().image.substring(0, proposalLength); >- _prefixResolved = true; >- } >- } >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTValueSuffix node, Object data) >- { >- // for now, only deal with the simple .id suffix >- Token lastToken = node.getLastToken(); >- if (node.jjtGetNumChildren() == 0) >- { >- if (!_prefixResolved >- && node.getFirstToken().kind == JSPELParserConstants.DOT) >- { >- if (lastToken.kind == JSPELParserConstants.IDENTIFIER) >- { >- if (testContainsCursor(node)) >- { >- _prefixType = ContentAssistStrategy.PREFIX_TYPE_DOT_COMPLETION; >- int proposalStartLength = _relativePos - lastToken.beginColumn; >- if (proposalStartLength < 0) { // Cursor after firstToken start but before lastToken start? >- proposalStartLength = 0; >- } >- _proposalStart = lastToken.image.substring(0, proposalStartLength); >- _prefixResolved = true; >- } >- // only include this suffix on the path if the cursor is >- // further to the right. Thus for x.^y we get a prefix "x" >- // and for x.y.^z we get "x.y" since this the part we must >- // resolve the prefix for >- else >- { >- _curPrefix += node.getFirstToken().image + lastToken.image; >- } >- } >- else if (lastToken == node.getFirstToken()) >- { >- if (testCursorImmediatelyAfter(node)) >- { >- _prefixType = ContentAssistStrategy.PREFIX_TYPE_DOT_COMPLETION; >- _prefixResolved = true; >- } >- } >- } >- >- return null; >- } >- >- if (node.getFirstToken().kind == JSPELParserConstants.LBRACKET) >- { >- // try to support ca inside the brackets >- node.childrenAccept(this, data); >- } >- >- Object retValue = node.childrenAccept(this, data); >- >- if (!_prefixResolved) >- { >- // if we haven't resolved the prefix yet, then we need >- // to append this suffix value >- _curPrefix += _fullText.substring(node.getFirstToken().beginColumn-1, node.getLastToken().endColumn); >- } >+ SymbolInfo res = null; >+ final ASTResolver astResolver = createASTResolver(context, elText); >+ if (astResolver != null && astResolver.findSymbolAtPos(relativePosition + context.getDocumentPosition() - 1)) { >+ ISymbol symbol = astResolver.getCurrentSymbol(); >+ Region region = new Region(astResolver.getCurrentSymbolStartpos() - context.getDocumentPosition(), astResolver.getCurrentSymbolLength()); >+ res = new SymbolInfo(symbol, region); > >- return retValue; > } >+ return res; >+ } > >- public Object visit(SimpleNode node, Object data) >- { >- return node.childrenAccept(this, data); >- } >- >- private boolean testCursorImmediatelyAfter(SimpleNode node) >- { >- return node.getLastToken().endColumn == _relativePos-1; >- } >- >- /** >- * "Containing a cursor" here is deemed to mean that current cursor >- * position as indicated by _relativePos, is either directly before, on or >- * directly after an expression. For example, in a Value expression like >- * >- * x x x . y y y . z z z >- * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ >- * 1 2 3 4 5 6 7 8 9 0 1 2 >- * >- * Position's 1-4 are on xxx, 5-8 are on yyy and 9-12 are on zzz >- * >- * @param node >- * @return true if the node "contains the cursor" (see above) >- */ >- private boolean testContainsCursor(SimpleNode node) >- { >- return (node.getFirstToken().beginColumn <= _relativePos >- && node.getLastToken().endColumn+1 >= _relativePos); >- >+ private static ASTResolver createASTResolver(IStructuredDocumentContext context, final String elText) { >+ ASTResolver res = null; >+ try { >+ final java.io.StringReader reader = new java.io.StringReader(elText); >+ final JSPELParser parser = new JSPELParser(reader); >+ final ASTExpression expr = parser.Expression(); >+ res = new ASTResolver(expr, context); >+ } catch (ParseException e) { >+ // TODO Do what? >+// System.out.println(e); > } >+ return res; > } >- >- private ContentAssistParser() >+ >+ private ContentAssistParser() > { > // utility class; not instantiable > } >Index: src/org/eclipse/jst/jsf/core/internal/contentassist/el/IdCompletionStrategy.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/internal/contentassist/el/IdCompletionStrategy.java,v >retrieving revision 1.2 >diff -u -r1.2 IdCompletionStrategy.java >--- src/org/eclipse/jst/jsf/core/internal/contentassist/el/IdCompletionStrategy.java 16 Apr 2007 19:53:23 -0000 1.2 >+++ src/org/eclipse/jst/jsf/core/internal/contentassist/el/IdCompletionStrategy.java 19 Nov 2007 23:11:03 -0000 >@@ -46,12 +46,11 @@ > /** > * Construct a strategy for completing an ID completion > * >- * @param prefixValue > * @param proposalStart - the part of the proposal which was already typed when user invoked autocomplete > */ >- public IdCompletionStrategy(final String prefixValue, String proposalStart) >+ public IdCompletionStrategy(final String proposalStart) > { >- super(ContentAssistStrategy.PREFIX_TYPE_ID_COMPLETION, prefixValue, proposalStart); >+ super(ContentAssistStrategy.PREFIX_TYPE_ID_COMPLETION, proposalStart); > } > > /** >Index: src/org/eclipse/jst/jsf/core/internal/contentassist/el/FunctionCompletionStrategy.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/core/internal/contentassist/el/FunctionCompletionStrategy.java,v >retrieving revision 1.2 >diff -u -r1.2 FunctionCompletionStrategy.java >--- src/org/eclipse/jst/jsf/core/internal/contentassist/el/FunctionCompletionStrategy.java 16 Apr 2007 19:53:23 -0000 1.2 >+++ src/org/eclipse/jst/jsf/core/internal/contentassist/el/FunctionCompletionStrategy.java 19 Nov 2007 23:11:01 -0000 >@@ -18,14 +18,9 @@ > > import org.eclipse.emf.edit.provider.ComposedAdapterFactory; > import org.eclipse.jface.text.contentassist.ICompletionProposal; >-import org.eclipse.jst.jsf.common.internal.types.CompositeType; >-import org.eclipse.jst.jsf.common.internal.types.IAssignable; >-import org.eclipse.jst.jsf.context.resolver.structureddocument.IDOMContextResolver; > import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; >-import org.eclipse.jst.jsf.context.resolver.structureddocument.ITaglibContextResolver; > import org.eclipse.jst.jsf.context.resolver.structureddocument.internal.ITextRegionContextResolver; > import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; >-import org.eclipse.jst.jsf.context.symbol.IInstanceSymbol; > import org.eclipse.jst.jsf.context.symbol.IMethodSymbol; > import org.eclipse.jst.jsf.context.symbol.IObjectSymbol; > import org.eclipse.jst.jsf.context.symbol.ISymbol; >@@ -34,14 +29,8 @@ > import org.eclipse.jst.jsf.context.symbol.provider.IContentProposalProvider.IProposalCreationFactory; > import org.eclipse.jst.jsf.designtime.resolver.ISymbolContextResolver; > import org.eclipse.jst.jsf.designtime.resolver.StructuredDocumentSymbolResolverFactory; >-import org.eclipse.jst.jsf.metadataprocessors.MetaDataEnabledProcessingFactory; >-import org.eclipse.jst.jsf.metadataprocessors.features.ELIsNotValidException; >-import org.eclipse.jst.jsf.metadataprocessors.features.IValidELValues; > import org.eclipse.jst.jsp.core.internal.regions.DOMJSPRegionContexts; > import org.eclipse.swt.graphics.Image; >-import org.w3c.dom.Attr; >-import org.w3c.dom.Element; >-import org.w3c.dom.Node; > > /** > * A completion strategy for function completions like: >@@ -54,116 +43,73 @@ > */ > public class FunctionCompletionStrategy extends ContentAssistStrategy > { >+ >+ private final ISymbol parentSymbol; >+ > /** >- * @param value >+ * @param parentSymbol > * @param proposalStart > */ >- public FunctionCompletionStrategy(String value, String proposalStart) >+ public FunctionCompletionStrategy(ISymbol parentSymbol, String proposalStart) > { >- super(ContentAssistStrategy.PREFIX_TYPE_DOT_COMPLETION, value, proposalStart); >+ super(ContentAssistStrategy.PREFIX_TYPE_DOT_COMPLETION, proposalStart); >+ this.parentSymbol = parentSymbol; > } > > public List getProposals(IStructuredDocumentContext context) > { > final List completionList = new ArrayList(); >- >- String[] ids = getValue().split("\\."); >- >- // if no suffixes, only one id >- if (ids.length < 1) >- { >- ids = new String[] {getValue()}; >- } >- > final ISymbolContextResolver symbolResolver = > StructuredDocumentSymbolResolverFactory.getInstance(). > getSymbolContextResolver(context); >- >- ISymbol symbol = null; >- >- if (symbolResolver != null) >- { >- symbol = symbolResolver.getVariable(ids[0]); >- } >- >- if (symbol instanceof IInstanceSymbol >- && ((IInstanceSymbol)symbol).isTypeResolved()) >+ >+ // if we get a completion symbol, get it's proposals >+ if (parentSymbol != null && parentSymbol instanceof IObjectSymbol) > { >- int curSuffixIdx = 1; >+ final List expectedMethodBindings = new ArrayList(); >+ ISymbol[] suffixes = getSymbols((IObjectSymbol) parentSymbol, >+ context, >+ symbolResolver, >+ expectedMethodBindings); >+ >+ final ComposedAdapterFactory factory = >+ new ComposedAdapterFactory( >+ ComposedAdapterFactory.Descriptor.Registry.INSTANCE); >+ final IProposalCreationFactory creationInfo = >+ new MyProposalFactory(context, getProposalStart().length(), >+ expectedMethodBindings); > >- while >- (curSuffixIdx < ids.length >- && symbol != null) >+ for (int i = 0; i < suffixes.length; i++) > { >- >- final ISymbol[] properties = >- symbolResolver.getProperties(symbol); >+ final ISymbol propSymbol = suffixes[i]; >+ final Object provider = >+ factory.adapt(propSymbol, IContentProposalProvider.class); > >- // set symbol to null because hasn't been found yet >- symbol = null; >- >- SEARCH_SYMBOL_NAME:for >- (int i = 0; i < properties.length; i++) >+ if (provider instanceof IContentProposalProvider) > { >- final ISymbol element = properties[i]; >- >- if (ids[curSuffixIdx].equals(element.getName())) >+ final ICompletionProposal[] proposal = >+ ((IContentProposalProvider) provider). >+ getProposals(propSymbol, creationInfo); >+ if (proposal != null) > { >- symbol = element; >- break SEARCH_SYMBOL_NAME; >- } >- } >- curSuffixIdx++; >- } >- >- // if we get a completion symbol, get it's proposals >- if (symbol instanceof IObjectSymbol) >- { >- final List expectedMethodBindings = new ArrayList(); >- ISymbol[] suffixes = getSymbols((IObjectSymbol) symbol, >- context, >- symbolResolver, >- expectedMethodBindings); >- >- final ComposedAdapterFactory factory = >- new ComposedAdapterFactory( >- ComposedAdapterFactory.Descriptor.Registry.INSTANCE); >- final IProposalCreationFactory creationInfo = >- new MyProposalFactory(context, getProposalStart().length(), >- expectedMethodBindings); >- >- for (int i = 0; i < suffixes.length; i++) >- { >- final ISymbol propSymbol = suffixes[i]; >- final Object provider = >- factory.adapt(propSymbol, IContentProposalProvider.class); >- >- if (provider instanceof IContentProposalProvider) >- { >- final ICompletionProposal[] proposal = >- ((IContentProposalProvider) provider). >- getProposals(propSymbol, creationInfo); >- if (proposal != null) >- { >- addProposalsMatchingProposalStart(completionList, >- proposal); >- } >+ addProposalsMatchingProposalStart(completionList, >+ proposal); > } > } > } > } >- >+ > return completionList; > } > >- private ISymbol[] getSymbols(IObjectSymbol symbol, >+ private ISymbol[] getSymbols(IObjectSymbol symbol, > IStructuredDocumentContext context, > ISymbolContextResolver symbolResolver, > List expectedMethodBindings) > { > List symbols = new ArrayList(); > >- if (isMethodBindingExpected(context, expectedMethodBindings)) >+ if (SymbolResolveUtil.isMethodBindingExpected(context, expectedMethodBindings)) > { > symbols.addAll(Arrays.asList( > symbolResolver.getMethods(symbol))); >@@ -174,64 +120,6 @@ > return (ISymbol[]) symbols.toArray(ISymbol.EMPTY_SYMBOL_ARRAY); > } > >- private boolean isMethodBindingExpected(IStructuredDocumentContext context, >- List expectedBindings) >- { >- boolean isMBExpected = false; // assume false until we find it true >- >- final IDOMContextResolver domResolver = >- IStructuredDocumentContextResolverFactory.INSTANCE. >- getDOMContextResolver(context); >- >- final Node curNode = domResolver.getNode(); >- >- if (curNode instanceof Attr) >- { >- final Attr attr = (Attr) curNode; >- final Element element = attr.getOwnerElement(); >- >- final ITaglibContextResolver taglibResolver = >- IStructuredDocumentContextResolverFactory.INSTANCE. >- getTaglibContextResolver(context); >- >- final String uri = taglibResolver.getTagURIForNodeName(element); >- >- final List elVals = >- MetaDataEnabledProcessingFactory.getInstance() >- .getAttributeValueRuntimeTypeFeatureProcessors >- (IValidELValues.class, context, uri, >- element.getLocalName(), attr.getLocalName()); >- >- for (final Iterator it = elVals.iterator(); it.hasNext();) >- { >- final IValidELValues validValues = (IValidELValues) it.next(); >- >- try >- { >- CompositeType type = validValues.getExpectedRuntimeType(); >- if (type != null >- && type.getAssignmentTypeMask() >- == IAssignable.ASSIGNMENT_TYPE_NONE) >- { >- isMBExpected = true; >- expectedBindings.addAll( >- Arrays.asList( >- validValues. >- getExpectedRuntimeType(). >- getSignatures())); >- } >- } >- catch (ELIsNotValidException e) >- { >- // do nothing >- } >- } >- } >- >- // default condition is no method binding >- return isMBExpected; >- } >- > private static class MyProposalFactory extends ProposalCreationFactoryAdapter > { > private final static int DEFAULT_RELEVANCE = 1; >@@ -276,7 +164,7 @@ > // see to do this > // if it's an array, we must check if we need to replace a > // preceding '.' >- if (replacementText.startsWith("[")) >+ if (replacementText.startsWith("[")) //$NON-NLS-1$ > { > ITextRegionContextResolver textResolver = > IStructuredDocumentContextResolverFactory.INSTANCE.getTextRegionResolver(_context); >Index: src/org/eclipse/jst/jsf/validation/internal/el/ASTSemanticValidator.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/validation/internal/el/ASTSemanticValidator.java,v >retrieving revision 1.6 >diff -u -r1.6 ASTSemanticValidator.java >--- src/org/eclipse/jst/jsf/validation/internal/el/ASTSemanticValidator.java 28 Jun 2007 21:39:10 -0000 1.6 >+++ src/org/eclipse/jst/jsf/validation/internal/el/ASTSemanticValidator.java 19 Nov 2007 23:11:06 -0000 >@@ -17,95 +17,32 @@ > import java.util.Iterator; > import java.util.List; > >-import org.eclipse.core.resources.IFile; > import org.eclipse.emf.common.util.Diagnostic; >-import org.eclipse.jst.jsf.common.internal.types.BooleanLiteralType; >-import org.eclipse.jst.jsf.common.internal.types.FloatLiteralType; >-import org.eclipse.jst.jsf.common.internal.types.IntegerLiteralType; >-import org.eclipse.jst.jsf.common.internal.types.LiteralType; >-import org.eclipse.jst.jsf.common.internal.types.MethodType; >-import org.eclipse.jst.jsf.common.internal.types.NullLiteralType; > import org.eclipse.jst.jsf.common.internal.types.SignatureBasedType; >-import org.eclipse.jst.jsf.common.internal.types.StringLiteralType; >-import org.eclipse.jst.jsf.common.internal.types.ValueType; >-import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; >-import org.eclipse.jst.jsf.context.resolver.structureddocument.IWorkspaceContextResolver; > import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; >-import org.eclipse.jst.jsf.context.symbol.IInstanceSymbol; >-import org.eclipse.jst.jsf.context.symbol.IPropertySymbol; >-import org.eclipse.jst.jsf.context.symbol.ISymbol; >-import org.eclipse.jst.jsf.context.symbol.internal.util.IObjectSymbolBasedValueType; >-import org.eclipse.jst.jsf.core.internal.JSFCorePlugin; >-import org.eclipse.jst.jsf.designtime.resolver.ISymbolContextResolver; >-import org.eclipse.jst.jsf.designtime.resolver.StructuredDocumentSymbolResolverFactory; > import org.eclipse.jst.jsf.validation.internal.ELValidationPreferences; >-import org.eclipse.jst.jsf.validation.internal.el.diagnostics.DiagnosticFactory; > import org.eclipse.jst.jsf.validation.internal.el.diagnostics.ValidationMessageFactory; >-import org.eclipse.jst.jsf.validation.internal.el.operators.BinaryOperator; >-import org.eclipse.jst.jsf.validation.internal.el.operators.BracketOperator; >-import org.eclipse.jst.jsf.validation.internal.el.operators.DotOperator; >-import org.eclipse.jst.jsf.validation.internal.el.operators.TernaryChoiceOperator; >-import org.eclipse.jst.jsf.validation.internal.el.operators.UnaryOperator; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTAddExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTAndExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTChoiceExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTEqualityExpression; > import org.eclipse.jst.jsp.core.internal.java.jspel.ASTExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTFunctionInvocation; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTLiteral; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTMultiplyExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTOperatorExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTOrExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTRelationalExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTUnaryExpression; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValue; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValuePrefix; >-import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValueSuffix; > import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParser; >-import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParserConstants; >-import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParserVisitor; > import org.eclipse.jst.jsp.core.internal.java.jspel.ParseException; >-import org.eclipse.jst.jsp.core.internal.java.jspel.SimpleNode; >-import org.eclipse.jst.jsp.core.internal.java.jspel.Token; > import org.eclipse.wst.validation.internal.core.Message; > import org.eclipse.wst.validation.internal.provisional.core.IMessage; > import org.eclipse.wst.validation.internal.provisional.core.IReporter; > import org.eclipse.wst.validation.internal.provisional.core.IValidator; > > >-class ASTSemanticValidator implements JSPELParserVisitor, IExpressionSemanticValidator >+/** This class creates validation messages for an EL expression. >+ */ >+public class ASTSemanticValidator extends ASTTraverser implements IExpressionSemanticValidator > { >- private final IFile _targetFile; >- private final ASTExpression _expr; >- private final IStructuredDocumentContext _context; >- private final ISymbolContextResolver _symbolResolver; > private final List<IMessage> _messages; >- private final EvaluationTracker _tracker; >- private final DiagnosticFactory _diagnosticFactory; > private final ELValidationPreferences _prefs; > private boolean _validatorHasBeenCalled; //=false > > ASTSemanticValidator(ASTExpression expr, IStructuredDocumentContext context, ELValidationPreferences prefs) > { >- final IWorkspaceContextResolver resolver = >- IStructuredDocumentContextResolverFactory. >- INSTANCE.getWorkspaceContextResolver(context); >- >- if (resolver != null) >- { >- _targetFile = (IFile) resolver.getResource(); >- } >- else >- { >- _targetFile = null; >- } >- >- _expr = expr; >- _context = context; >- _symbolResolver = StructuredDocumentSymbolResolverFactory.getInstance().getSymbolContextResolver(_context); >+ super(expr, context); > _messages = new ArrayList<IMessage>(); >- _tracker = new EvaluationTracker(); >- _diagnosticFactory = new DiagnosticFactory(); > _prefs = prefs; > } > >@@ -114,392 +51,17 @@ > */ > public void validate() > { >- _expr.jjtAccept(this, _tracker); >+ getExpr().jjtAccept(this, getTracker()); > _validatorHasBeenCalled = true; > } > >- public Object visit(ASTAddExpression node, Object data) >- { >- performBinaryEvaluation(node, (EvaluationTracker)data); >- return data; >- } >- >- public Object visit(ASTAndExpression node, Object data) >- { >- performBinaryEvaluation(node, (EvaluationTracker)data); >- return data; >- } >- >- public Object visit(ASTChoiceExpression node, Object data) >- { >- if (node.jjtGetNumChildren() != 3) >- { >- throw new AssertionError("Binary operators should always have two sub-expressions"); >- } >- >- // evaluate choice argument >- node.jjtGetChild(0).jjtAccept(this, data); >- final ValueType choiceArg = ((EvaluationTracker)data).getValueType(); >- // evaluate when true argument >- node.jjtGetChild(1).jjtAccept(this, data); >- final ValueType whenTrueArg = ((EvaluationTracker)data).getValueType(); >- //evaluate when false argument >- node.jjtGetChild(2).jjtAccept(this, data); >- final ValueType whenFalseArg = ((EvaluationTracker)data).getValueType(); >- >- >- if (choiceArg != null && whenTrueArg != null && whenFalseArg != null) >- { >- final TernaryChoiceOperator operator = >- new TernaryChoiceOperator(_diagnosticFactory); >- >- final Diagnostic diagnostic = >- operator.validate(choiceArg/* whenTrueArg, whenFalseArg*/); >- >- if (diagnostic.getSeverity() != Diagnostic.OK) >- { >- final Token firstToken = node.getFirstToken(); >- final int offset = _context.getDocumentPosition() + firstToken.beginColumn - 1; >- final int length = node.getLastToken().endColumn - firstToken.beginColumn+1; >- final Message message = >- ValidationMessageFactory.createFromDiagnostic(diagnostic, >- offset, length, _targetFile, _prefs); >- _messages.add(message); >- } >- >- ((EvaluationTracker)data).setType(operator.perform(choiceArg, whenTrueArg, whenFalseArg)); >- } >- else >- { >- ((EvaluationTracker)data).setType(null); >- } >- >- return data; >- } >- >- public Object visit(ASTEqualityExpression node, Object data) >- { >- performBinaryEvaluation(node, (EvaluationTracker)data); >- return data; >+ protected void addMessageFromDiagnostic(final Diagnostic diagnostic, final int offset, final int length) { >+ final Message message = >+ ValidationMessageFactory.createFromDiagnostic(diagnostic, >+ offset, length, getTargetFile(), _prefs); >+ _messages.add(message); > } > >- public Object visit(ASTExpression node, Object data) { >- return node.childrenAccept(this, data); >- } >- >- public Object visit(ASTFunctionInvocation node, Object data) >- { >- // when we see a function invocation, null the type >- // we do not validate function invocations currently >- Object retVal = node.childrenAccept(this, data); >- ((EvaluationTracker)data).setType(null); >- return retVal; >- } >- >- public Object visit(ASTLiteral node, Object data) >- { >- // note, there is an implicit assumption here that literals >- // are all terminals (leafs in the tree) >- if (node.jjtGetNumChildren() > 0) >- { >- throw new AssertionError("Literals should be terminal"); >- } >- >- LiteralType type = null; >- >- Token literalToken = node.getFirstToken(); >- >- switch (literalToken.kind) >- { >- case JSPELParserConstants.STRING_LITERAL: >- type = new StringLiteralType(stripQuotes(literalToken.image)); >- break; >- >- case JSPELParserConstants.INTEGER_LITERAL: >- type = new IntegerLiteralType(Long.parseLong(literalToken.image)); >- break; >- >- case JSPELParserConstants.FLOATING_POINT_LITERAL: >- type = new FloatLiteralType(Double.parseDouble(literalToken.image)); >- break; >- >- case JSPELParserConstants.FALSE: >- type = BooleanLiteralType.FALSE; >- break; >- >- case JSPELParserConstants.TRUE: >- type = BooleanLiteralType.TRUE; >- break; >- >- case JSPELParserConstants.NULL: >- type = NullLiteralType.SINGLETON; >- break; >- >- default: >- JSFCorePlugin.log("Unknown EL literal: " +literalToken.toString(), new Throwable("This throwable simply used to mark a stack trace")); >- } >- >- ((EvaluationTracker)data).setType(type); >- return data; >- } >- >- private String stripQuotes(String stringLiteral) >- { >- if (stringLiteral.startsWith("'") >- || stringLiteral.startsWith("\"")) >- >- { >- if (stringLiteral.length() > 2) >- { >- // take 'literal' -> literal >- return stringLiteral.substring(1, stringLiteral.length()-1); >- } >- // if only two characters, then the empty string >- return ""; >- } >- >- return stringLiteral; >- } >- >- public Object visit(ASTMultiplyExpression node, Object data) >- { >- performBinaryEvaluation(node, (EvaluationTracker)data); >- return data; >- } >- >- public Object visit(ASTOrExpression node, Object data) >- { >- performBinaryEvaluation(node, (EvaluationTracker)data); >- return data; >- } >- >- public Object visit(ASTRelationalExpression node, Object data) >- { >- performBinaryEvaluation(node, (EvaluationTracker)data); >- return data; >- } >- >- public Object visit(ASTUnaryExpression node, Object data) >- { >- // assertion here is that this expression decomposes: >- // UnaryExpr -> Value >- // UnaryExpr -> UnaryOp UnaryExpression >- // since UnaryOp is a terminal (-,!,not,empty) node will >- // always have exactly one child >- node.childrenAccept(this, data); >- final SignatureBasedType type = ((EvaluationTracker)data).getType(); >- >- if (type != null) >- { >- final Token firstToken = node.getFirstToken(); >- if (UnaryOperator.isUnaryOperator(firstToken)) >- { >- if (type instanceof ValueType) >- { >- final UnaryOperator unaryOp = UnaryOperator.createUnaryOperator(firstToken, _diagnosticFactory); >- final Diagnostic diagnostic = unaryOp.validate((ValueType)type); >- >- if (diagnostic.getSeverity() != Diagnostic.OK) >- { >- final int offset = _context.getDocumentPosition() + firstToken.beginColumn - 1; >- final int length = node.getLastToken().endColumn - firstToken.beginColumn+1; >- final Message message = >- ValidationMessageFactory.createFromDiagnostic(diagnostic, offset, length, _targetFile,_prefs); >- _messages.add(message); >- } >- >- ((EvaluationTracker)data). >- setType(unaryOp.performOperation ((ValueType)type)); >- } >- // cannot apply operations to method bindings >- else >- { >- final int offset = _context.getDocumentPosition() + >- firstToken.beginColumn - 1; >- final int length = node.getLastToken().endColumn - >- firstToken.beginColumn+1; >- >- _messages.add(ValidationMessageFactory. >- createFromDiagnostic(_diagnosticFactory.create_CANNOT_APPLY_OPERATOR_TO_METHOD_BINDING(), >- offset, length, _targetFile,_prefs)); >- } >- } >- } >- >- return data; >- } >- >- public Object visit(ASTValue node, final Object data) { >- ValueExpressionTracker tracker = new ValueExpressionTracker(); >- >- ((EvaluationTracker)data).setValueTracker(tracker); >- >- node.childrenAccept(this, data); >- >- SignatureBasedType type = ((EvaluationTracker)data).getType(); >- >- // now check the tracker. If the last property in the expression >- // is non-null (i.e. the value has one or more suffices) then we >- // to very the leaf node (i.e. 'z' in #{x.y.z}) is more than just >- // an intermediate value used to get to other properties >- if (type instanceof IObjectSymbolBasedValueType >- && ((IObjectSymbolBasedValueType)type).getSymbol() instanceof IPropertySymbol >- && ((IPropertySymbol)((IObjectSymbolBasedValueType)type).getSymbol()).isIntermediate()) >- { >- final int problemStartOffset = tracker.getCurPropertySymbolOffset(); >- final int length = tracker.getCurPropertySymbolLength(); >- _messages.add(ValidationMessageFactory.createFromDiagnostic( >- _diagnosticFactory.create_MEMBER_IS_INTERMEDIATE( >- ((IPropertySymbol)((IObjectSymbolBasedValueType)type).getSymbol()).getName()) >- , problemStartOffset, length, _targetFile, _prefs)); >- } >- >- return data; >- } >- >- public Object visit(ASTValuePrefix node, final Object data) >- { >- if (node.jjtGetNumChildren() == 0) >- { >- final Token token = node.getFirstToken(); >- final String image = token.image; >- >- final ISymbol symbol = _symbolResolver.getVariable(image); >- >- if (symbol == null) >- { >- final int problemStartOffset = >- _context.getDocumentPosition() + token.beginColumn - 1; >- final int length = token.endColumn - token.beginColumn + 1; >- >- final Diagnostic diag = >- _diagnosticFactory.create_VARIABLE_NOT_FOUND(image); >- >- if (diag.getSeverity() != Diagnostic.OK) >- { >- _messages.add( >- ValidationMessageFactory.createFromDiagnostic(diag, >- problemStartOffset, length, _targetFile, _prefs)); >- } >- } >- else if (symbol instanceof IInstanceSymbol) >- { >- final IObjectSymbolBasedValueType symbolType = >- IObjectSymbolBasedValueType.getInstance(symbol); >- ((EvaluationTracker) data).setType(symbolType); >- } >- } >- >- return node.childrenAccept(this, data); >- } >- >- public Object visit(final ASTValueSuffix node, final Object data) >- { >- final ValueExpressionTracker tracker = ((EvaluationTracker) data).getValueTracker(); >- final SignatureBasedType type = ((EvaluationTracker) data).getType(); >- >- if (type instanceof IObjectSymbolBasedValueType) >- { >- final IObjectSymbolBasedValueType symbolType = >- (IObjectSymbolBasedValueType) type; >- final Token firstToken = node.getFirstToken(); >- >- if (node.jjtGetNumChildren() == 0 >- && firstToken.kind == JSPELParserConstants.DOT) >- { >- final Token dotId = node.getLastToken(); >- >- final int startOffset = >- _context.getDocumentPosition() + dotId.beginColumn - 1; >- final int length = dotId.endColumn - dotId.beginColumn + 1; >- >- final DotOperator dotOp = new DotOperator(_diagnosticFactory, _targetFile); >- >- final StringLiteralType suffixLiteral = new StringLiteralType(dotId.image); >- Diagnostic diag = >- dotOp.validate(symbolType, >- suffixLiteral); >- >- if (diag.getSeverity() != Diagnostic.OK) >- { >- _messages.add(ValidationMessageFactory.createFromDiagnostic( >- diag, startOffset, length, _targetFile, _prefs)); >- ((EvaluationTracker) data).setType(null); >- } >- else >- { >-// // if the base (value-a) is a map, then using the bracket value-a['y'] type >-// // syntax is recommended. Note that we do this here instead of >-// // DotOperator so that we don't tie the default property resolver >-// // behaviour to that operator class. If someone changes the rules >-// // of how the prop resolver interprets the base, then they may want to >-// // write their own validator that doesn't do this >-// if (symbolType.getSymbol().supportsCoercion(TypeConstants.TYPE_MAP)) >-// { >-// _messages.add(ValidationMessageFactory.createFromDiagnostic( >-// DiagnosticFactory.create_BINARY_OP_DOT_WITH_VALUEA_MAP_SHOULD_USE_ARRAY >-// (symbolType.getSymbol().getName(), dotId.image), >-// startOffset, length, _targetFile)); >-// } >- >- ((EvaluationTracker) data).setType(dotOp.performOperation(symbolType, >- suffixLiteral)); >- tracker.setCurMemberSymbol(startOffset, length); >- } >- >- // we finished with the single dot suffix here >- return data; >- } >- else if (firstToken.kind == JSPELParserConstants.LBRACKET) >- { >- final EvaluationTracker subExprTracker = new EvaluationTracker(); >- node.childrenAccept(this, subExprTracker); >- >- final SignatureBasedType subExprType = subExprTracker.getType(); >- >- if (subExprType instanceof ValueType) >- { >- final Token lastToken = node.getLastToken(); >- final int startOffset = >- _context.getDocumentPosition() + firstToken.beginColumn - 1; >- final int length = lastToken.endColumn - firstToken.beginColumn + 1; >- >- final BracketOperator bracketOperator = new BracketOperator(_diagnosticFactory, _targetFile); >- >- final Diagnostic diag = >- bracketOperator.validate(symbolType, >- (ValueType)subExprType); >- >- if (diag.getSeverity() != Diagnostic.OK) >- { >- _messages.add(ValidationMessageFactory.createFromDiagnostic( >- diag, >- startOffset, length, _targetFile, _prefs)); >- ((EvaluationTracker) data).setType(null); >- } >- else >- { >- ((EvaluationTracker) data).setType(bracketOperator.performOperation(symbolType, >- (ValueType)subExprType)); >- tracker.setCurMemberSymbol(startOffset, length); >- } >- } >- // we are finished with the bracketed suffix at this point. >- return data; >- } >- } >- >- // don't bother to accept children, since if we haven't done >- // something above, there's not much sensible we can do with it >- // clear the type first though >- ((EvaluationTracker) data).setType(null); >- return data; //node.childrenAccept(this, data); >- } >- >- public Object visit(SimpleNode node, Object data) { >- return node.childrenAccept(this, data); >- } >- > /** > * Copies stored messages into the validation reporter > * @param validator >@@ -519,73 +81,6 @@ > } > } > >- private void performBinaryEvaluation(ASTOperatorExpression node, EvaluationTracker tracker) >- { >- if (node.jjtGetNumChildren() < 2) >- { >- throw new AssertionError("Binary operators should always have at least two sub-expressions"); >- } >- else if (node.getOperatorTokens().size() != node.jjtGetNumChildren()-1) >- { >- throw new AssertionError("Binary operators should always have one operator token less than number of sub-expressions"); >- } >- >- // evaluate left-most argument >- node.jjtGetChild(0).jjtAccept(this, tracker); >- >- ValueType curType = getValueTypeForBinaryOperation(tracker.getType(), (SimpleNode) node.jjtGetChild(0)); >- >- for (int child = 1; child < node.jjtGetNumChildren(); child++) >- { >- // evaluate next argument running left-to-right >- node.jjtGetChild(child).jjtAccept(this, tracker); >- final ValueType secondType = >- getValueTypeForBinaryOperation(tracker.getType(), (SimpleNode) node.jjtGetChild(child)); >- >- if (curType != null && secondType != null) >- { >- final BinaryOperator operator = >- BinaryOperator.getBinaryOperator((Token)node.getOperatorTokens().get(child-1), _diagnosticFactory, _context); >- >- final Diagnostic diagnostic = operator.validate(curType, secondType); >- >- if (diagnostic.getSeverity() != Diagnostic.OK) >- { >- final Token firstToken = node.getFirstToken(); >- final int offset = _context.getDocumentPosition() + firstToken.beginColumn - 1; >- final int length = node.getLastToken().endColumn - firstToken.beginColumn+1; >- final Message message = >- ValidationMessageFactory.createFromDiagnostic >- (diagnostic, offset, length, _targetFile, _prefs); >- _messages.add(message); >- } >- >- curType = operator.performOperation(curType, secondType); >- } >- } >- >- tracker.setType(curType); >- } >- >- private ValueType getValueTypeForBinaryOperation(SignatureBasedType type, SimpleNode node) >- { >- if (type instanceof ValueType) >- { >- return (ValueType) type; >- } >- else if (type instanceof MethodType) >- { >- final int offset = _context.getDocumentPosition() + node.getFirstToken().beginColumn - 1; >- final int length = node.getLastToken().endColumn - node.getFirstToken().beginColumn+1; >- >- _messages.add(ValidationMessageFactory.createFromDiagnostic >- (_diagnosticFactory.create_CANNOT_APPLY_OPERATOR_TO_METHOD_BINDING(), >- offset, length, _targetFile, _prefs)); >- } >- >- return null; >- } >- > /* (non-Javadoc) > * @see org.eclipse.jst.jsf.validation.internal.el.IExpressionSemanticValidator#getMessages() > */ >@@ -593,7 +88,7 @@ > { > if (!_validatorHasBeenCalled) > { >- throw new AssertionError("Should not call getMessages before validate has been called"); >+ throw new AssertionError("Should not call getMessages before validate has been called"); //$NON-NLS-1$ > } > return _messages; > } >@@ -603,7 +98,7 @@ > */ > public SignatureBasedType getExpressionType() > { >- return _tracker.getType(); >+ return getTracker().getType(); > } > > /** >@@ -613,7 +108,7 @@ > */ > public static void main(String[] args) throws IOException, ParseException > { >- String elText = ""; >+ String elText = ""; //$NON-NLS-1$ > int nextCharacter; > > while(((nextCharacter = System.in.read()) != -1)) >@@ -624,9 +119,9 @@ > { > JSPELParser parser = JSPELParser.createParser(elText); > ASTExpression expr = parser.Expression(); >- expr.dump(""); >+ expr.dump(""); //$NON-NLS-1$ > >- elText = ""; >+ elText = ""; //$NON-NLS-1$ > } > else > { >@@ -634,4 +129,10 @@ > } > } > } >+ >+ @Override >+ protected boolean isValidate() { >+ return true; >+ } >+ > } >Index: src/org/eclipse/jst/jsf/validation/internal/el/ValueExpressionTracker.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/validation/internal/el/ValueExpressionTracker.java,v >retrieving revision 1.3 >diff -u -r1.3 ValueExpressionTracker.java >--- src/org/eclipse/jst/jsf/validation/internal/el/ValueExpressionTracker.java 28 Jun 2007 21:39:10 -0000 1.3 >+++ src/org/eclipse/jst/jsf/validation/internal/el/ValueExpressionTracker.java 19 Nov 2007 23:11:06 -0000 >@@ -12,35 +12,92 @@ > > package org.eclipse.jst.jsf.validation.internal.el; > >+import org.eclipse.jst.jsf.context.symbol.ISymbol; >+ > > class ValueExpressionTracker > { >- private int _curPropertySymbolOffset; >- private int _curPropertySymbolLength; >- >+ private ISymbol _currentSymbol; >+ private ISymbol _parentSymbol; >+ >+ private int _currentSymbolOffset; >+ private int _currentSymbolLength; >+ private String _currentSuffixOperator; >+ >+ ValueExpressionTracker() { >+ super(); >+ _parentSymbol = null; >+ _currentSymbol = null; >+ _currentSuffixOperator = null; >+ } >+ > /** > * @param offset > * @param length > */ >- public void setCurMemberSymbol(int offset, int length) >+ public void setCurrentSymbolPos(int offset, int length) > { >- _curPropertySymbolOffset = offset; >- _curPropertySymbolLength = length; >+ _currentSymbolOffset = offset; >+ _currentSymbolLength = length; > } > > /** > * @return the offset of the current property symbol or 0 if no current property symbol > */ >- public int getCurPropertySymbolOffset() >+ public int getCurrentSymbolOffset() > { >- return _curPropertySymbolOffset; >+ return _currentSymbolOffset; > } > > /** > * @return the length of the current property symbol or 0 if no current property symbol > */ >- public int getCurPropertySymbolLength() >+ public int getCurrentSymbolLength() > { >- return _curPropertySymbolLength; >+ return _currentSymbolLength; >+ } >+ >+ /** >+ * @return the parent ISymbol the current symbol is a member of, if any >+ */ >+ public ISymbol getParentSymbol() { >+ return _parentSymbol; >+ } >+ >+ /** Sets the parent ISymbol the current symbol is a member of. >+ * @param parentSymbol >+ */ >+ public void setParentSymbol(ISymbol parentSymbol) { >+ _parentSymbol = parentSymbol; >+ } >+ >+ /** >+ * @return the current ISymbol >+ */ >+ public ISymbol getCurrentSymbol() { >+ return _currentSymbol; >+ } >+ >+ /** Sets the current ISymbol. >+ * @param symbol >+ */ >+ public void setCurrentSymbol(ISymbol symbol) { >+ _currentSymbol = symbol; >+ } >+ >+ /** >+ * @return the suffix operator ("." or "[") preceding the current symbol, <code>null</code> if >+ * current symbol is no member symbol. >+ */ >+ public String getCurrentSuffixOperator() { >+ return _currentSuffixOperator; >+ } >+ >+ /** >+ * @param suffixOperator - the suffix operator ("." or "[") preceding the current symbol, <code>null</code> if >+ * current symbol is no member symbol. >+ */ >+ public void setCurrentSuffixOperator(String suffixOperator) { >+ _currentSuffixOperator = suffixOperator; > } > } >Index: src/org/eclipse/jst/jsf/validation/internal/JSPSemanticsValidator.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/validation/internal/JSPSemanticsValidator.java,v >retrieving revision 1.10 >diff -u -r1.10 JSPSemanticsValidator.java >--- src/org/eclipse/jst/jsf/validation/internal/JSPSemanticsValidator.java 11 Jun 2007 20:55:28 -0000 1.10 >+++ src/org/eclipse/jst/jsf/validation/internal/JSPSemanticsValidator.java 19 Nov 2007 23:11:06 -0000 >@@ -104,7 +104,8 @@ > protected void validateFile(IFile file, IReporter reporter) { > IStructuredModel model = null; > if (DEBUG) >- System.out.println("executing JSPSemanticsValidator.validateFile"); >+ System.out.println("executing JSPSemanticsValidator.validateFile"); //$NON-NLS-1$ >+// boolean jspProcessorCreated = false; > try { > model = StructuredModelManager.getModelManager().getModelForRead(file); > >@@ -113,6 +114,10 @@ > ValidationPreferences prefs= new ValidationPreferences(JSFCorePlugin.getDefault().getPreferenceStore()); > prefs.load(); > DiagnosticFactory diagnosticFactory = new DiagnosticFactory(); >+ /* Performance: ensures that JSPModelProcessor is kept alive while validating this file >+ * instead of being created anew for every variable lookup: */ >+// JSPModelProcessor.get(file); >+// jspProcessorCreated = true; // make sure it gets disposed in finally block (ref-counted!) > > // zero the containment validation count for each mondel > containmentValidationCount = 0; >@@ -130,16 +135,19 @@ > } > catch (CoreException e) > { >- JSFCorePlugin.log("Error validating JSF", e); >+ JSFCorePlugin.log("Error validating JSF", e); //$NON-NLS-1$ > } > catch (IOException e) > { >- JSFCorePlugin.log("Error validating JSF", e); >+ JSFCorePlugin.log("Error validating JSF", e); //$NON-NLS-1$ > } > finally > { > if (null != model) > model.releaseFromRead(); >+// if (jspProcessorCreated) >+// JSPModelProcessor.dispose(file); >+// jspProcessorCreated = false; > > // zero the containment count before exit > containmentValidationCount = 0; >@@ -151,7 +159,7 @@ > */ > public void validate(IRegion dirtyRegion, IValidationContext helper, IReporter reporter) { > if (DEBUG) >- System.out.println("exec JSPSemanticsValidator.validateRegion"); >+ System.out.println("exec JSPSemanticsValidator.validateRegion"); //$NON-NLS-1$ > > ValidationPreferences prefs = new ValidationPreferences(JSFCorePlugin.getDefault().getPreferenceStore()); > prefs.load(); >@@ -221,13 +229,13 @@ > } > > if (DEBUG) >- System.out.println(addDebugSpacer(1)+"tagName= "+ (tagName!= null ? tagName : "null") +": uri= "+(uri != null ? uri : "null") ); >+ System.out.println(addDebugSpacer(1)+"tagName= "+ (tagName!= null ? tagName : "null") +": uri= "+(uri != null ? uri : "null") ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ > } > else if (type == DOMRegionContext.XML_TAG_ATTRIBUTE_NAME) > { > attrName = resolver.getNode().getNodeName(); > if (DEBUG) >- System.out.println(addDebugSpacer(2)+"attrName= "+(attrName != null ? attrName : "null" )); >+ System.out.println(addDebugSpacer(2)+"attrName= "+(attrName != null ? attrName : "null" )); //$NON-NLS-1$ //$NON-NLS-2$ > if (uri != null && tagName != null) > { > // TODO: validateAttribute(context, region, uri, resolver.getNode(), file); >@@ -255,7 +263,7 @@ > { > // else validate as static attribute value > if (DEBUG) >- System.out.println(addDebugSpacer(3)+"attrVal= "+(attributeVal != null ? attributeVal : "null") ); >+ System.out.println(addDebugSpacer(3)+"attrVal= "+(attributeVal != null ? attributeVal : "null") ); //$NON-NLS-1$ //$NON-NLS-2$ > > if (uri != null && tagName != null && attrName != null) > validateAttributeValue(context, uri, tagName, attrName, attributeVal, reporter, file); >@@ -313,7 +321,7 @@ > final String elText = parentRegion.getText(content); > > if (DEBUG) >- System.out.println(addDebugSpacer(3)+"EL attrVal= "+elText); >+ System.out.println(addDebugSpacer(3)+"EL attrVal= "+elText); //$NON-NLS-1$ > > // EL validation is user configurable because > // it can be computationally costly. >@@ -446,10 +454,10 @@ > if (!vv.isEmpty()){ > for (Iterator it = vv.iterator();it.hasNext();){ > IValidValues v = (IValidValues)it.next(); >- if (attributeVal == null) attributeVal = "";//ensure to be non-null >+ if (attributeVal == null) attributeVal = "";//ensure to be non-null //$NON-NLS-1$ > if (!v.isValidValue(attributeVal.trim())){ > if (DEBUG) >- System.out.println(addDebugSpacer(4)+"NOT VALID "); >+ System.out.println(addDebugSpacer(4)+"NOT VALID "); //$NON-NLS-1$ > > for (Iterator msgs = v.getValidationMessages().iterator();msgs.hasNext();){ > IValidationMessage msg = (IValidationMessage)msgs.next(); >@@ -461,11 +469,11 @@ > } > else > if (DEBUG) >- System.out.println(addDebugSpacer(5) + "VALID "); >+ System.out.println(addDebugSpacer(5) + "VALID "); //$NON-NLS-1$ > } > } > else if (DEBUG) >- System.out.println(addDebugSpacer(4)+"NO META DATA "); >+ System.out.println(addDebugSpacer(4)+"NO META DATA "); //$NON-NLS-1$ > } > > private IMessage createValidationMessage(IStructuredDocumentContext context, String attributeValue, int severity, String msg, IFile file){ >@@ -522,8 +530,8 @@ > } > > private String addDebugSpacer(int count){ >- String TAB = "\t"; >- StringBuffer ret = new StringBuffer(""); >+ String TAB = "\t"; //$NON-NLS-1$ >+ StringBuffer ret = new StringBuffer(""); //$NON-NLS-1$ > for(int i=0;i<=count;i++){ > ret.append(TAB); > } >@@ -565,7 +573,7 @@ > { > final Trait trait = > TaglibDomainMetaDataQueryHelper.getTrait >- (entity, "containment-constraint"); >+ (entity, "containment-constraint"); //$NON-NLS-1$ > > if (trait != null) > { >@@ -576,7 +584,7 @@ > > // TODO: need generalized factory mechanism for registering and constructing > // algorithms. >- if (!"xpath".equals(algorithm)) >+ if (!"xpath".equals(algorithm)) //$NON-NLS-1$ > { > return; > } >@@ -597,12 +605,12 @@ > } > catch(InvalidExpressionException e) > { >- JSFCorePlugin.log(e, "Problem with expression: "+expr+" on node "+node); >+ JSFCorePlugin.log(e, "Problem with expression: "+expr+" on node "+node); //$NON-NLS-1$ //$NON-NLS-2$ > return; > } > catch (EvaluationException e) > { >- JSFCorePlugin.log(e, "Problem evaluating expression: "+expr+" on node "+node); >+ JSFCorePlugin.log(e, "Problem evaluating expression: "+expr+" on node "+node); //$NON-NLS-1$ //$NON-NLS-2$ > return; > } > >@@ -620,7 +628,7 @@ > { > containmentValidationCount++; // found a violation > >- final String messagePattern = "Tag {0} is missing required parent tag \"{1}\" ({2})"; >+ final String messagePattern = Messages.JSPSemanticsValidator_0; > > List data = diag.getData(); > >Index: src/org/eclipse/jst/jsf/validation/internal/el/operators/DotOperator.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/validation/internal/el/operators/DotOperator.java,v >retrieving revision 1.5 >diff -u -r1.5 DotOperator.java >--- src/org/eclipse/jst/jsf/validation/internal/el/operators/DotOperator.java 5 Jul 2007 16:56:29 -0000 1.5 >+++ src/org/eclipse/jst/jsf/validation/internal/el/operators/DotOperator.java 19 Nov 2007 23:11:07 -0000 >@@ -13,7 +13,6 @@ > import org.eclipse.core.resources.IFile; > import org.eclipse.emf.common.util.Diagnostic; > import org.eclipse.jst.jsf.common.internal.types.LiteralType; >-import org.eclipse.jst.jsf.common.internal.types.SignatureBasedType; > import org.eclipse.jst.jsf.common.internal.types.ValueType; > import org.eclipse.jst.jsf.context.symbol.internal.util.IObjectSymbolBasedValueType; > import org.eclipse.jst.jsf.validation.internal.el.diagnostics.DiagnosticFactory; >@@ -35,36 +34,23 @@ > super(file, diagnosticFactory); > } > >- protected SignatureBasedType handlePerformObjectSymbolValue( >+ protected OperationResult handlePerformObjectSymbolValue( > IObjectSymbolBasedValueType firstArg, ValueType secondArg) > { > // the dot operator (unlike the bracket) can only treat firstArg as > // a named property accessor object > // if we don't have a literal value with which to derive value-b, then > // we can't get a property >- if (secondArg instanceof LiteralType) >+ if (secondArg instanceof LiteralType || secondArg == null) > { > return handlePerformNamedPropertyAccessorBase(firstArg, (LiteralType)secondArg); > } >- return null; >- } >- >- public Diagnostic validateObjectSymbolValue(IObjectSymbolBasedValueType firstArg, >- ValueType secondArg) >- { >- Diagnostic diag = Diagnostic.OK_INSTANCE; >- >- if (secondArg instanceof LiteralType) >- { >- diag = validateNamedPropertyAccessorBase(firstArg, (LiteralType) secondArg); >- } >- >- return diag; >+ return new OperationResult(Diagnostic.OK_INSTANCE, null); > } > > @Override > protected String getOperatorName() > { >- return Messages.getString("DotOperator.Name"); >+ return Messages.getString("DotOperator.Name"); //$NON-NLS-1$ > } > } >\ No newline at end of file >Index: src/org/eclipse/jst/jsf/validation/internal/el/operators/MemberAccessorOperator.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/validation/internal/el/operators/MemberAccessorOperator.java,v >retrieving revision 1.6 >diff -u -r1.6 MemberAccessorOperator.java >--- src/org/eclipse/jst/jsf/validation/internal/el/operators/MemberAccessorOperator.java 5 Jul 2007 16:56:29 -0000 1.6 >+++ src/org/eclipse/jst/jsf/validation/internal/el/operators/MemberAccessorOperator.java 19 Nov 2007 23:11:07 -0000 >@@ -39,6 +39,29 @@ > */ > public abstract class MemberAccessorOperator > { >+ >+ /** This class combines the SignatureBasedType of the result and the Diagnostic when >+ * performing an operation. >+ */ >+ public static class OperationResult { >+ /**the diagnostic >+ */ >+ public final Diagnostic diagnostic; >+ /**the resulting type >+ */ >+ public final SignatureBasedType resultType; >+ /**Constructs a new OperationResult using the given Diagnostic and SignatureBasedType >+ * @param diagnostic >+ * @param resultType >+ */ >+ public OperationResult(Diagnostic diagnostic, SignatureBasedType resultType) { >+ super(); >+ this.diagnostic = diagnostic; >+ this.resultType = resultType; >+ } >+ >+ } >+ > /** > * The source file for the EL expression in which this operator > * is being evaluated. >@@ -64,130 +87,100 @@ > } > > /** >- * @param firstArg >- * @param secondArg >- * @return the result of validating the dot operation with these arguments. >- */ >- public Diagnostic validate(ValueType firstArg, ValueType secondArg) >- { >- if (!(firstArg instanceof IObjectSymbolBasedValueType)) >- { >- throw new AssertionError("The first argument of the member operator must always be a symbol resolvable value type"); >+ * @param firstArg - type of first argument, may be null if unknown >+ * @param secondArg - type of second argument, may be null if unknown >+ * @return OperationResult (none-null) containing: the resolved type for >+ * the operation or null if not computable, and a Diagnostic describing >+ * the validation result >+ */ >+ public OperationResult performOperation(ValueType firstArg, ValueType secondArg) >+ { >+ if (firstArg == null) { >+ //can't find any errors or calculate anything if type of firstArg is unknown >+ return new OperationResult(Diagnostic.OK_INSTANCE, null); > } >- >- if (TypeCoercer.typeIsNull(secondArg.getSignature())) >- { >- return _diagnosticFactory.create_BINARY_OP_DOT_WITH_VALUEB_NULL(getOperatorName()); >- } >- >- return validateObjectSymbolValue((IObjectSymbolBasedValueType) firstArg, secondArg); >- } >- >- /** >- * @param firstArg >- * @param secondArg >- * @return the diagnostic for member(firstArg, secondArg) >- */ >- protected abstract Diagnostic validateObjectSymbolValue(IObjectSymbolBasedValueType firstArg, ValueType secondArg); >- >- /** >- * @param firstArg >- * @param secondArg >- * @return a validation of a named property accessible base (map or bean) given >- * an a literal key argument >- */ >- protected Diagnostic validateNamedPropertyAccessorBase(IObjectSymbolBasedValueType firstArg >- , LiteralType secondArg) >- { >- final IObjectSymbol curBaseSymbol = firstArg.getSymbol(); >- >- final ISymbol nextSymbol = getMemberSymbol(firstArg.getSymbol(), >- secondArg.getLiteralValueRaw()); >- >- // if the x in x.y is an unconstrained map an it returns >- // a java.lang.Object, then return null. We can't really say >- // anything meaningful about such a property anyway. >- // TODO: do we need to refine the type descriptor on such >- // a property object to make this more precise? >- if (curBaseSymbol.supportsCoercion(TypeConstants.TYPE_MAP) >- && nextSymbol instanceof IPropertySymbol >- && TypeConstants.TYPE_JAVAOBJECT.equals(((IPropertySymbol)nextSymbol).getTypeDescriptor().getTypeSignature())) >- { >- // if we get a symbol back that's a generic object coming from a map >- // then stop validating; we can't tell anything for sure >- return Diagnostic.OK_INSTANCE; >- } >- >- if (nextSymbol == null) >- { >- return _diagnosticFactory.create_MEMBER_NOT_FOUND(secondArg.getLiteralValue() >- ,firstArg.getSymbol().getName()); >- } >- >- return Diagnostic.OK_INSTANCE; >- } >- >- /** >- * @param firstArg >- * @param secondArg >- * @return the resolved type for the operation or null if not computable >- */ >- public SignatureBasedType performOperation(ValueType firstArg, ValueType secondArg) >- { > if (!(firstArg instanceof IObjectSymbolBasedValueType)) > { >- return null; >+ throw new AssertionError("The first argument of the member operator must always be a symbol resolvable value type"); //$NON-NLS-1$ > } > > // per JSP.2.3.4, if value-b is null, then return null (not literal null) >- if (TypeCoercer.typeIsNull(secondArg.getSignature())) >+ if (secondArg != null && TypeCoercer.typeIsNull(secondArg.getSignature())) > { >- return null; >+ return new OperationResult(_diagnosticFactory.create_BINARY_OP_DOT_WITH_VALUEB_NULL(getOperatorName()), null); > } > > return handlePerformObjectSymbolValue((IObjectSymbolBasedValueType)firstArg, secondArg); > } > > /** >- * @param firstArg -- represents value-a (expr-a after step 1) in JSP.2.3.4 >- * @param secondArg -- represents value-b (expr-b after step 3) in JSP.2.3.4 >- * @return the new ValueType for this operation or null >+ * @param firstArg -- represents value-a (expr-a after step 1) in JSP.2.3.4, not null >+ * @param secondArg -- represents value-b (expr-b after step 3) in JSP.2.3.4, may be null >+ * @return the OperationResult for this operation > */ >- protected abstract SignatureBasedType handlePerformObjectSymbolValue(IObjectSymbolBasedValueType firstArg >+ protected abstract OperationResult handlePerformObjectSymbolValue(IObjectSymbolBasedValueType firstArg > , ValueType secondArg); > > /** >- * @param firstArg >- * @param secondArg >- * @return the resolved type for firstArg[secondArg] treating firstArg as a type >+ * @param firstArg - type of firstArg, none-null >+ * @param secondArg - type of secondArg, may be null if unknown >+ * @return OperationResult for firstArg[secondArg] treating firstArg as a type > * that uses a named property accessor (i.e. a map or bean but not a list or array) > * or null if unresolved > */ >- protected SignatureBasedType handlePerformNamedPropertyAccessorBase(IObjectSymbolBasedValueType firstArg >+ protected OperationResult handlePerformNamedPropertyAccessorBase(IObjectSymbolBasedValueType firstArg > , LiteralType secondArg) > { >- final ISymbol symbol = >- getMemberSymbol(firstArg.getSymbol(), secondArg.getLiteralValueRaw()); >+ final IObjectSymbol curBaseSymbol = firstArg.getSymbol(); >+ final ISymbol nextSymbol; >+ if (secondArg != null) { >+ nextSymbol = getMemberSymbol(curBaseSymbol, secondArg.getLiteralValueRaw()); >+ } else { >+ nextSymbol = getGenericMemberSymbol(curBaseSymbol); >+ } > >- if (symbol instanceof IPropertySymbol) >+ if (nextSymbol == null) > { >- return new IObjectSymbolBasedValueType((IPropertySymbol)symbol); >+ final String property = secondArg == null? "(unknown)" : secondArg.getLiteralValue(); >+ return new OperationResult(_diagnosticFactory.create_MEMBER_NOT_FOUND(property, >+ curBaseSymbol.getName()), null); > } >- else if (symbol instanceof IMethodSymbol) >+ >+ if (nextSymbol instanceof IPropertySymbol) > { >- return new IMethodSymbolBasedType((IMethodSymbol) symbol); >+ return new OperationResult(Diagnostic.OK_INSTANCE, new IObjectSymbolBasedValueType((IPropertySymbol)nextSymbol)); >+ } >+ else if (nextSymbol instanceof IMethodSymbol) >+ { >+ return new OperationResult(Diagnostic.OK_INSTANCE, new IMethodSymbolBasedType((IMethodSymbol) nextSymbol)); > } > >- // fall-through and return null > // per JSP2.3.4 steps 5 and 6, return null literal if map, null (error) otherwise > if (firstArg.isInstanceOf(TypeConstants.TYPE_MAP)) > { >- return NullLiteralType.SINGLETON; >+ return new OperationResult(Diagnostic.OK_INSTANCE, NullLiteralType.SINGLETON); > } >- return null; >+ //TODO Can this happen? Is this really "ok"? >+ return new OperationResult(Diagnostic.OK_INSTANCE, null); > } > > /** >+ * @param baseSymbol >+ * @return The best possible symbol for a member of <code>baseSymbol</code> when the name of the member >+ * is unknown/invalid (works for instance if <code>baseSymbol</code> is a typed map). >+ * May be null if none can be determined. >+ */ >+ protected ISymbol getGenericMemberSymbol(IObjectSymbol baseSymbol) { >+ /* TODO HACK How to determine result type of 'get' if no argument is known? Why >+ * does DefaultDTPropertyResolver assumes Map keys are Strings?? >+ */ >+ if (baseSymbol.getTypeDescriptor().instanceOf(TypeConstants.TYPE_MAP)) { >+ return getPropertySymbol(baseSymbol, "(unknown)"); //$NON-NLS-1$ >+ } >+ return null; >+ } >+ >+ /** > * @param symbol > * @param name > * @return the member symbol of 'symbol' corresponding to 'name' or >@@ -229,7 +222,7 @@ > return resolver.getProperty(symbol,name); > } > >- JSFCorePlugin.log("Error acquiring property resolver", new Throwable()); >+ JSFCorePlugin.log("Error acquiring property resolver", new Throwable()); //$NON-NLS-1$ > return null; > } > >@@ -248,7 +241,7 @@ > return resolver.getMethod(symbol, name); > } > >- JSFCorePlugin.log("Error acquiring property resolver", new Throwable()); >+ JSFCorePlugin.log("Error acquiring property resolver", new Throwable()); //$NON-NLS-1$ > return null; > > } >Index: src/org/eclipse/jst/jsf/validation/internal/el/operators/BracketOperator.java >=================================================================== >RCS file: /cvsroot/webtools/org.eclipse.jsf/components/jsf/plugins/org.eclipse.jst.jsf.core/src/org/eclipse/jst/jsf/validation/internal/el/operators/BracketOperator.java,v >retrieving revision 1.6 >diff -u -r1.6 BracketOperator.java >--- src/org/eclipse/jst/jsf/validation/internal/el/operators/BracketOperator.java 5 Jul 2007 16:56:29 -0000 1.6 >+++ src/org/eclipse/jst/jsf/validation/internal/el/operators/BracketOperator.java 19 Nov 2007 23:11:06 -0000 >@@ -14,7 +14,6 @@ > import org.eclipse.emf.common.util.Diagnostic; > import org.eclipse.jdt.core.Signature; > import org.eclipse.jst.jsf.common.internal.types.LiteralType; >-import org.eclipse.jst.jsf.common.internal.types.SignatureBasedType; > import org.eclipse.jst.jsf.common.internal.types.TypeCoercer; > import org.eclipse.jst.jsf.common.internal.types.TypeCoercionException; > import org.eclipse.jst.jsf.common.internal.types.TypeConstants; >@@ -34,8 +33,6 @@ > */ > public class BracketOperator extends MemberAccessorOperator > { >- private static final String OPERATOR_NAME_ARRAY_ACCESSOR = "array ('[]') accessor"; >- > /** > * @param diagnosticFactory > * @param file >@@ -45,7 +42,7 @@ > super(file, diagnosticFactory); > } > >- protected SignatureBasedType handlePerformObjectSymbolValue( >+ protected OperationResult handlePerformObjectSymbolValue( > IObjectSymbolBasedValueType firstArg, ValueType secondArg) > { > // per JSP.2.3.4 step 5.2, if value-a is a list or array access >@@ -63,103 +60,67 @@ > // we can't get a property > if (secondArg instanceof LiteralType) > { >+ // TODO: Verify type > return handlePerformNamedPropertyAccessorBase(firstArg, (LiteralType)secondArg); > } >- >- return null; >+ // TODO: Verify type if possible >+ return handlePerformNamedPropertyAccessorBase(firstArg, null); > } > >- protected Diagnostic validateObjectSymbolValue(IObjectSymbolBasedValueType firstArg, >- ValueType secondArg) >- { >- // per JSP.2.3.4 step 5.2, if value-a is a list or array access >- if (firstArg.isInstanceOf(TypeConstants.TYPE_LIST) >- || firstArg.getSymbol().getTypeDescriptor().isArray()) >- { >- return validateNumericPropertyAccessorBase(firstArg, secondArg); >- } >- >- // per JSP.2.3.4 step 5, if value-a is a map or if it is not >- // a list or array (and therefore a bean), treat it as named property accessed object >- // if firstArg is a map then we must treat the access like a map.get(secondArg) >- if (secondArg instanceof LiteralType) >- { >- return validateNamedPropertyAccessorBase(firstArg, (LiteralType) secondArg); >- } >- // otherwise, there's nothing we can guarantee >- return Diagnostic.OK_INSTANCE; >- } >- >- private Diagnostic validateNumericPropertyAccessorBase(IObjectSymbolBasedValueType firstArg, >- ValueType secondArg) >- { >- try >- { >- // secondArg must successfully coerce to integer >- TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature())); >- >- if (secondArg instanceof LiteralType) >- { >- // this will throw a TypeCoercionExceptino if it won't >- // coerce >- Integer integerValue = >- (Integer) ((LiteralType)secondArg).coerceToNumber(Integer.class); >- >- if (integerValue.intValue() < 0) >- { >- return _diagnosticFactory.create_POSSIBLE_ARRAY_INDEX_OUT_OF_BOUNDS(integerValue); >- } >- } >- else >- { >- // if the argument is a non-literal string, we can't verify >- // that the coercion to integer won't throw an exception >- // at runtime >- if (TypeCoercer.typeIsString(secondArg.getSignature())) >- { >- return _diagnosticFactory.create_UNARY_OP_STRING_CONVERSION_NOT_GUARANTEED(OPERATOR_NAME_ARRAY_ACCESSOR); >- } >- } >- >- // TODO: attempt to detect ArrayIndexOutOfBoundsException >- return Diagnostic.OK_INSTANCE; >- } >- catch (TypeCoercionException e) >- { >- return _diagnosticFactory.create_BINARY_OP_COULD_NOT_MAKE_NUMERIC_COERCION(OPERATOR_NAME_ARRAY_ACCESSOR); >- } >- } >- >- private SignatureBasedType handlePerformNumericPropertyAccessorBase(IObjectSymbolBasedValueType firstArg, >+ private OperationResult handlePerformNumericPropertyAccessorBase(IObjectSymbolBasedValueType firstArg, > ValueType secondArg) > { >+ Diagnostic diagnostic = Diagnostic.OK_INSTANCE; > AbstractDTPropertyResolver propResolver = getPropertyResolver(); >+ > int index = 0; >- if (secondArg instanceof LiteralType) >- { >+ if (secondArg != null) { > try { >- index = ((LiteralType)secondArg).coerceToNumber(Integer.class).intValue(); >+ // secondArg must successfully coerce to integer >+ TypeCoercer.coerceToNumber(TypeTransformer.transformBoxPrimitives(secondArg.getSignature())); >+ if (secondArg instanceof LiteralType) >+ { >+ final Number indexInt = ((LiteralType)secondArg).coerceToNumber(Integer.class); >+ if (indexInt != null) { >+ index = indexInt.intValue(); >+ if (index < 0) { >+ diagnostic = _diagnosticFactory.create_POSSIBLE_ARRAY_INDEX_OUT_OF_BOUNDS(Integer.valueOf(index)); >+ index = 0; // fix index for further validation >+ } >+ } >+ } >+ else >+ { >+ // if the argument is a non-literal string, we can't verify >+ // that the coercion to integer won't throw an exception >+ // at runtime >+ if (TypeCoercer.typeIsString(secondArg.getSignature())) >+ { >+ diagnostic = _diagnosticFactory.create_UNARY_OP_STRING_CONVERSION_NOT_GUARANTEED(getOperatorName()); >+ } >+ } >+ // TODO: attempt to detect ArrayIndexOutOfBoundsException > } catch (TypeCoercionException e) { >- // suppress, just use index = 0 >- // this maybe should be an assertion... >+ diagnostic = _diagnosticFactory.create_BINARY_OP_COULD_NOT_MAKE_NUMERIC_COERCION(getOperatorName()); >+ // continue, just use index = 0 > } > } >- >+ > final ISymbol symbol = > propResolver.getProperty(firstArg.getSymbol(), index); > > if (symbol instanceof IObjectSymbol) > { >- return IObjectSymbolBasedValueType.getInstance(symbol); >+ return new OperationResult(diagnostic, IObjectSymbolBasedValueType.getInstance(symbol)); > } > >- // if can't be resolved, return null >- return null; >+ // can't be resolved: >+ return new OperationResult(diagnostic, null); > } > > @Override > protected String getOperatorName() > { >- return Messages.getString("BracketOperator.Name"); >+ return Messages.getString("BracketOperator.Name"); //$NON-NLS-1$ > } > } >Index: src/org/eclipse/jst/jsf/validation/internal/Messages.java >=================================================================== >RCS file: src/org/eclipse/jst/jsf/validation/internal/Messages.java >diff -N src/org/eclipse/jst/jsf/validation/internal/Messages.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jst/jsf/validation/internal/Messages.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,21 @@ >+package org.eclipse.jst.jsf.validation.internal; >+ >+import org.eclipse.osgi.util.NLS; >+ >+class Messages extends NLS { >+ private static final String BUNDLE_NAME = "org.eclipse.jst.jsf.validation.internal.messages"; //$NON-NLS-1$ >+ >+ /** >+ * see messages.properties >+ */ >+ public static String JSPSemanticsValidator_0; >+ >+ static { >+ // initialize resource bundle >+ NLS.initializeMessages(BUNDLE_NAME, Messages.class); >+ } >+ >+ private Messages() { >+ // do nothing; no external instantiation >+ } >+} >Index: src/org/eclipse/jst/jsf/validation/internal/messages.properties >=================================================================== >RCS file: src/org/eclipse/jst/jsf/validation/internal/messages.properties >diff -N src/org/eclipse/jst/jsf/validation/internal/messages.properties >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jst/jsf/validation/internal/messages.properties 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,1 @@ >+JSPSemanticsValidator_0=Tag {0} is missing required parent tag "{1}" ({2}) >Index: src/org/eclipse/jst/jsf/validation/internal/el/ASTResolver.java >=================================================================== >RCS file: src/org/eclipse/jst/jsf/validation/internal/el/ASTResolver.java >diff -N src/org/eclipse/jst/jsf/validation/internal/el/ASTResolver.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jst/jsf/validation/internal/el/ASTResolver.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,154 @@ >+package org.eclipse.jst.jsf.validation.internal.el; >+ >+import org.eclipse.jst.jsf.common.internal.types.SignatureBasedType; >+import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; >+import org.eclipse.jst.jsf.context.symbol.ISymbol; >+import org.eclipse.jst.jsf.context.symbol.internal.util.IObjectSymbolBasedValueType; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValue; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValuePrefix; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValueSuffix; >+import org.eclipse.jst.jsp.core.internal.java.jspel.SimpleNode; >+ >+/** This class is used to resolve a symbol at a given text position in an EL expression. >+ */ >+public class ASTResolver extends ASTTraverser { >+ >+ private int _targetPosRelative; >+ private ValueExpressionTracker _targetValueTracker; >+ private boolean _targetFound; >+ >+ /**Create a new ASTResolver to resolve symbols in an EL expression >+ * @param expr - the EL expression >+ * @param context - document context >+ */ >+ public ASTResolver(ASTExpression expr, IStructuredDocumentContext context) { >+ super(expr, context); >+ } >+ >+ /**Determines info for the symbol at the given text position. Use {@link #getCurrentSymbol()}, >+ * {@link #getCurrentSymbolStartpos()}, {@link #getCurrentSymbolLength()}, {@link #getParentSymbol()} >+ * in order to get the information after calling this method. >+ * @param pos - the <i>absolute</i> text position in document of the symbol to resolve >+ * @return true, if a symbol could be resolved for the given position >+ */ >+ public boolean findSymbolAtPos(int pos) >+ { >+ _targetPosRelative = pos - getContext().getDocumentPosition() + 1; >+ _targetFound = false; >+ _targetValueTracker = null; >+ getExpr().jjtAccept(this, getTracker()); >+ return _targetFound; >+ } >+ >+ @Override >+ public Object visit(ASTValue node, Object data) { >+ if (!_targetFound) { >+ return super.visit(node, data); >+ } >+ return data; >+ } >+ >+ @Override >+ public Object visit(ASTValuePrefix node, Object data) { >+ if (!_targetFound) { >+ return super.visit(node, data); >+ } >+ return data; >+ } >+ >+ @Override >+ public Object visit(ASTValueSuffix node, Object data) { >+ if (!_targetFound) { >+ return super.visit(node, data); >+ } >+ return data; >+ } >+ >+ @Override >+ protected void updateValueTracker(final ValueExpressionTracker tracker, final SimpleNode node, >+ final IObjectSymbolBasedValueType parentType, final String suffixOperator, >+ final SignatureBasedType resultType, int startOffset, int length) { >+ if (_targetFound) { >+ return; >+ } >+ super.updateValueTracker(tracker, node, parentType, suffixOperator, resultType, startOffset, length); >+ if (containsTargetPos(node)) { >+ _targetValueTracker = tracker; >+ _targetFound = true; >+ } >+ } >+ >+ /** >+ * "Containing the target position" here is deemed to mean that the >+ * position as indicated by _targetPosRelative, is either directly before, on or >+ * directly after an expression. For example, in a Value expression like >+ * >+ * x x x . y y y . z z z >+ * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ >+ * 1 2 3 4 5 6 7 8 9 0 1 2 >+ * >+ * Position's 1-4 are on xxx, 5-8 are on yyy and 9-12 are on zzz >+ * >+ * @param node >+ * @return true if the node "contains the cursor" (see above) >+ */ >+ private boolean containsTargetPos(SimpleNode node) >+ { >+ return (node.getFirstToken().beginColumn <= _targetPosRelative >+ && node.getLastToken().endColumn+1 >= _targetPosRelative); >+ >+ } >+ >+ /**Returns the found symbol. Use this only after you have called {@link #findSymbolAtPos(int)}! >+ * @return the ISymbol that has been found at the given position >+ */ >+ public ISymbol getCurrentSymbol() { >+ if (_targetValueTracker != null) { >+ return _targetValueTracker.getCurrentSymbol(); >+ } >+ return null; >+ } >+ >+ /**Returns the found symbol's start position. Use this only after you have called {@link #findSymbolAtPos(int)}! >+ * @return the <i>absolute</i> start position in document of the symbol found >+ */ >+ public int getCurrentSymbolStartpos() { >+ if (_targetValueTracker != null) { >+ return _targetValueTracker.getCurrentSymbolOffset(); >+ } >+ return 0; >+ } >+ >+ /**Returns the found symbol's length. Use this only after you have called {@link #findSymbolAtPos(int)}! >+ * @return the length of the symbol found >+ */ >+ public int getCurrentSymbolLength() { >+ if (_targetValueTracker != null) { >+ return _targetValueTracker.getCurrentSymbolLength(); >+ } >+ return 0; >+ } >+ >+ /**Returns the parent ISymbol of the found symbol. Use this only after you have called {@link #findSymbolAtPos(int)}! >+ * @return the ISymbol the current symbol is a member of, if any. >+ */ >+ public ISymbol getParentSymbol() { >+ if (_targetValueTracker != null) { >+ return _targetValueTracker.getParentSymbol(); >+ } >+ return null; >+ } >+ >+ /** >+ * @return the suffix operator ("." or "[") preceding the current symbol, <code>null</code> if >+ * current symbol is no member symbol. >+ */ >+ public String getCurrentSuffixOperator() { >+ if (_targetValueTracker != null) { >+ return _targetValueTracker.getCurrentSuffixOperator(); >+ } >+ return null; >+ } >+ >+} >Index: src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolInfo.java >=================================================================== >RCS file: src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolInfo.java >diff -N src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolInfo.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolInfo.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,31 @@ >+package org.eclipse.jst.jsf.core.internal.contentassist.el; >+ >+import org.eclipse.jface.text.Region; >+import org.eclipse.jst.jsf.context.symbol.ISymbol; >+ >+/** >+ * class contains a symbol and it's region >+ * >+ */ >+public class SymbolInfo { >+ >+ /** the symbol >+ */ >+ public ISymbol symbol; >+ /** the region of the symbol, relative to EL string >+ */ >+ public Region relativeRegion; >+ >+ /**Creates new SymbolInfo >+ * @param symbol >+ * @param relativeRegion - region relative to EL string >+ */ >+ public SymbolInfo(ISymbol symbol, Region relativeRegion) { >+ super(); >+ this.symbol = symbol; >+ this.relativeRegion = relativeRegion; >+ } >+ >+ >+ >+} >Index: src/org/eclipse/jst/jsf/validation/internal/el/ASTTraverser.java >=================================================================== >RCS file: src/org/eclipse/jst/jsf/validation/internal/el/ASTTraverser.java >diff -N src/org/eclipse/jst/jsf/validation/internal/el/ASTTraverser.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jst/jsf/validation/internal/el/ASTTraverser.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,623 @@ >+package org.eclipse.jst.jsf.validation.internal.el; >+ >+import org.eclipse.core.resources.IFile; >+import org.eclipse.emf.common.util.Diagnostic; >+import org.eclipse.jst.jsf.common.internal.types.BooleanLiteralType; >+import org.eclipse.jst.jsf.common.internal.types.FloatLiteralType; >+import org.eclipse.jst.jsf.common.internal.types.IntegerLiteralType; >+import org.eclipse.jst.jsf.common.internal.types.LiteralType; >+import org.eclipse.jst.jsf.common.internal.types.MethodType; >+import org.eclipse.jst.jsf.common.internal.types.NullLiteralType; >+import org.eclipse.jst.jsf.common.internal.types.SignatureBasedType; >+import org.eclipse.jst.jsf.common.internal.types.StringLiteralType; >+import org.eclipse.jst.jsf.common.internal.types.ValueType; >+import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; >+import org.eclipse.jst.jsf.context.resolver.structureddocument.IWorkspaceContextResolver; >+import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; >+import org.eclipse.jst.jsf.context.symbol.IInstanceSymbol; >+import org.eclipse.jst.jsf.context.symbol.IPropertySymbol; >+import org.eclipse.jst.jsf.context.symbol.ISymbol; >+import org.eclipse.jst.jsf.context.symbol.internal.util.IMethodSymbolBasedType; >+import org.eclipse.jst.jsf.context.symbol.internal.util.IObjectSymbolBasedValueType; >+import org.eclipse.jst.jsf.core.internal.JSFCorePlugin; >+import org.eclipse.jst.jsf.designtime.resolver.ISymbolContextResolver; >+import org.eclipse.jst.jsf.designtime.resolver.StructuredDocumentSymbolResolverFactory; >+import org.eclipse.jst.jsf.validation.internal.el.diagnostics.DiagnosticFactory; >+import org.eclipse.jst.jsf.validation.internal.el.operators.BinaryOperator; >+import org.eclipse.jst.jsf.validation.internal.el.operators.BracketOperator; >+import org.eclipse.jst.jsf.validation.internal.el.operators.DotOperator; >+import org.eclipse.jst.jsf.validation.internal.el.operators.TernaryChoiceOperator; >+import org.eclipse.jst.jsf.validation.internal.el.operators.UnaryOperator; >+import org.eclipse.jst.jsf.validation.internal.el.operators.MemberAccessorOperator.OperationResult; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTAddExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTAndExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTChoiceExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTEqualityExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTFunctionInvocation; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTLiteral; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTMultiplyExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTOperatorExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTOrExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTRelationalExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTUnaryExpression; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValue; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValuePrefix; >+import org.eclipse.jst.jsp.core.internal.java.jspel.ASTValueSuffix; >+import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParserConstants; >+import org.eclipse.jst.jsp.core.internal.java.jspel.JSPELParserVisitor; >+import org.eclipse.jst.jsp.core.internal.java.jspel.SimpleNode; >+import org.eclipse.jst.jsp.core.internal.java.jspel.Token; >+ >+/** >+ * Common superclass for traversing an EL expression >+ */ >+public class ASTTraverser implements JSPELParserVisitor { >+ >+ private final IStructuredDocumentContext _context; >+ private final DiagnosticFactory _diagnosticFactory; >+ private final IFile _targetFile; >+ private final ASTExpression _expr; >+ private final ISymbolContextResolver _symbolResolver; >+ private final EvaluationTracker _tracker; >+ >+ /**Creates a new ASTTraverser for a given expression and document context. >+ * @param expr >+ * @param context >+ */ >+ protected ASTTraverser(ASTExpression expr, IStructuredDocumentContext context) >+ { >+ final IWorkspaceContextResolver resolver = >+ IStructuredDocumentContextResolverFactory. >+ INSTANCE.getWorkspaceContextResolver(context); >+ >+ if (resolver != null) >+ { >+ _targetFile = (IFile) resolver.getResource(); >+ } >+ else >+ { >+ _targetFile = null; >+ } >+ >+ _expr = expr; >+ _context = context; >+ _symbolResolver = StructuredDocumentSymbolResolverFactory.getInstance().getSymbolContextResolver(_context); >+ _tracker = new EvaluationTracker(); >+ _diagnosticFactory = new DiagnosticFactory(); >+ } >+ >+ public Object visit(ASTAddExpression node, Object data) >+ { >+ performBinaryEvaluation(node, (EvaluationTracker)data); >+ return data; >+ } >+ >+ public Object visit(ASTAndExpression node, Object data) >+ { >+ performBinaryEvaluation(node, (EvaluationTracker)data); >+ return data; >+ } >+ >+ public Object visit(ASTChoiceExpression node, Object data) >+ { >+ if (node.jjtGetNumChildren() != 3) >+ { >+ throw new AssertionError("Binary operators should always have two sub-expressions"); //$NON-NLS-1$ >+ } >+ >+ // evaluate choice argument >+ node.jjtGetChild(0).jjtAccept(this, data); >+ final ValueType choiceArg = ((EvaluationTracker)data).getValueType(); >+ // evaluate when true argument >+ node.jjtGetChild(1).jjtAccept(this, data); >+ final ValueType whenTrueArg = ((EvaluationTracker)data).getValueType(); >+ //evaluate when false argument >+ node.jjtGetChild(2).jjtAccept(this, data); >+ final ValueType whenFalseArg = ((EvaluationTracker)data).getValueType(); >+ >+ >+ if (choiceArg != null && whenTrueArg != null && whenFalseArg != null) >+ { >+ final TernaryChoiceOperator operator = >+ new TernaryChoiceOperator(_diagnosticFactory); >+ >+ if (isValidate()) >+ { >+ final Diagnostic diagnostic = >+ operator.validate(choiceArg/* whenTrueArg, whenFalseArg*/); >+ >+ if (diagnostic.getSeverity() != Diagnostic.OK) >+ { >+ final Token firstToken = node.getFirstToken(); >+ final int offset = calcTokenOffset(firstToken); >+ final int length = node.getLastToken().endColumn - firstToken.beginColumn+1; >+ addMessageFromDiagnostic(diagnostic, offset, length); >+ } >+ } >+ >+ ((EvaluationTracker)data).setType(operator.perform(choiceArg, whenTrueArg, whenFalseArg)); >+ } >+ else >+ { >+ ((EvaluationTracker)data).setType(null); >+ } >+ >+ return data; >+ } >+ >+ public Object visit(ASTEqualityExpression node, Object data) >+ { >+ performBinaryEvaluation(node, (EvaluationTracker)data); >+ return data; >+ } >+ >+ public Object visit(ASTExpression node, Object data) { >+ return node.childrenAccept(this, data); >+ } >+ >+ public Object visit(ASTFunctionInvocation node, Object data) >+ { >+ // when we see a function invocation, null the type >+ // we do not validate function invocations currently >+ Object retVal = node.childrenAccept(this, data); >+ ((EvaluationTracker)data).setType(null); >+ return retVal; >+ } >+ >+ public Object visit(ASTLiteral node, Object data) >+ { >+ // note, there is an implicit assumption here that literals >+ // are all terminals (leafs in the tree) >+ if (node.jjtGetNumChildren() > 0) >+ { >+ throw new AssertionError("Literals should be terminal"); //$NON-NLS-1$ >+ } >+ >+ LiteralType type = null; >+ >+ Token literalToken = node.getFirstToken(); >+ >+ switch (literalToken.kind) >+ { >+ case JSPELParserConstants.STRING_LITERAL: >+ type = new StringLiteralType(stripQuotes(literalToken.image)); >+ break; >+ >+ case JSPELParserConstants.INTEGER_LITERAL: >+ type = new IntegerLiteralType(Long.parseLong(literalToken.image)); >+ break; >+ >+ case JSPELParserConstants.FLOATING_POINT_LITERAL: >+ type = new FloatLiteralType(Double.parseDouble(literalToken.image)); >+ break; >+ >+ case JSPELParserConstants.FALSE: >+ type = BooleanLiteralType.FALSE; >+ break; >+ >+ case JSPELParserConstants.TRUE: >+ type = BooleanLiteralType.TRUE; >+ break; >+ >+ case JSPELParserConstants.NULL: >+ type = NullLiteralType.SINGLETON; >+ break; >+ >+ default: >+ JSFCorePlugin.log("Unknown EL literal: " +literalToken.toString(), new Throwable("This throwable simply used to mark a stack trace")); //$NON-NLS-1$//$NON-NLS-2$ >+ } >+ >+ ((EvaluationTracker)data).setType(type); >+ return data; >+ } >+ >+ public Object visit(ASTMultiplyExpression node, Object data) >+ { >+ performBinaryEvaluation(node, (EvaluationTracker)data); >+ return data; >+ } >+ >+ public Object visit(ASTOrExpression node, Object data) >+ { >+ performBinaryEvaluation(node, (EvaluationTracker)data); >+ return data; >+ } >+ >+ public Object visit(ASTRelationalExpression node, Object data) >+ { >+ performBinaryEvaluation(node, (EvaluationTracker)data); >+ return data; >+ } >+ >+ public Object visit(ASTUnaryExpression node, Object data) >+ { >+ // assertion here is that this expression decomposes: >+ // UnaryExpr -> Value >+ // UnaryExpr -> UnaryOp UnaryExpression >+ // since UnaryOp is a terminal (-,!,not,empty) node will >+ // always have exactly one child >+ node.childrenAccept(this, data); >+ final SignatureBasedType type = ((EvaluationTracker)data).getType(); >+ >+ if (type != null) >+ { >+ final Token firstToken = node.getFirstToken(); >+ if (UnaryOperator.isUnaryOperator(firstToken)) >+ { >+ if (type instanceof ValueType) >+ { >+ final UnaryOperator unaryOp = UnaryOperator.createUnaryOperator(firstToken, _diagnosticFactory); >+ if (isValidate()) >+ { >+ final Diagnostic diagnostic = unaryOp.validate((ValueType)type); >+ >+ if (diagnostic.getSeverity() != Diagnostic.OK) >+ { >+ final int offset = calcTokenOffset(firstToken); >+ final int length = node.getLastToken().endColumn - firstToken.beginColumn+1; >+ addMessageFromDiagnostic(diagnostic, offset, length); >+ } >+ } >+ >+ ((EvaluationTracker)data). >+ setType(unaryOp.performOperation ((ValueType)type)); >+ } >+ // cannot apply operations to method bindings >+ else >+ { >+ if (isValidate()) >+ { >+ final int offset = calcTokenOffset(firstToken); >+ final int length = node.getLastToken().endColumn - >+ firstToken.beginColumn+1; >+ >+ addMessageFromDiagnostic(_diagnosticFactory.create_CANNOT_APPLY_OPERATOR_TO_METHOD_BINDING(), offset, length); >+ } >+ } >+ } >+ } >+ >+ return data; >+ } >+ >+ public Object visit(ASTValue node, final Object data) { >+ ValueExpressionTracker tracker = new ValueExpressionTracker(); >+ >+ ((EvaluationTracker)data).setValueTracker(tracker); >+ >+ node.childrenAccept(this, data); >+ >+ SignatureBasedType type = ((EvaluationTracker)data).getType(); >+ >+ // now check the tracker. If the last property in the expression >+ // is non-null (i.e. the value has one or more suffices) then we >+ // to very the leaf node (i.e. 'z' in #{x.y.z}) is more than just >+ // an intermediate value used to get to other properties >+ if (type instanceof IObjectSymbolBasedValueType >+ && ((IObjectSymbolBasedValueType)type).getSymbol() instanceof IPropertySymbol >+ && ((IPropertySymbol)((IObjectSymbolBasedValueType)type).getSymbol()).isIntermediate()) >+ { >+ if (isValidate()) >+ { >+ final int problemStartOffset = tracker.getCurrentSymbolOffset(); >+ final int length = tracker.getCurrentSymbolLength(); >+ addMessageFromDiagnostic(_diagnosticFactory.create_MEMBER_IS_INTERMEDIATE( >+ ((IPropertySymbol)((IObjectSymbolBasedValueType)type).getSymbol()).getName()) >+ , problemStartOffset, length); >+ } >+ } >+ >+ return data; >+ } >+ >+ public Object visit(ASTValuePrefix node, final Object data) >+ { >+ if (node.jjtGetNumChildren() == 0) >+ { >+ final Token token = node.getFirstToken(); >+ final String image = token.image; >+ >+ final ISymbol symbol = _symbolResolver.getVariable(image); >+ >+ final int problemStartOffset = >+ calcTokenOffset(token); >+ final int length = calcTokenLength(token); >+ >+ ValueExpressionTracker valueTracker = ((EvaluationTracker) data).getValueTracker(); >+ IObjectSymbolBasedValueType symbolType = null; >+ >+ if (symbol == null) >+ { >+ if (isValidate()) >+ { >+ final Diagnostic diag = >+ _diagnosticFactory.create_VARIABLE_NOT_FOUND(image); >+ >+ if (diag.getSeverity() != Diagnostic.OK) >+ { >+ addMessageFromDiagnostic(diag, problemStartOffset, length); >+ } >+ } >+ } >+ else if (symbol instanceof IInstanceSymbol) >+ { >+ symbolType = IObjectSymbolBasedValueType.getInstance(symbol); >+ ((EvaluationTracker) data).setType(symbolType); >+ } >+ updateValueTracker(valueTracker, node, null, null, symbolType, problemStartOffset, length); >+ } >+ >+ return node.childrenAccept(this, data); >+ } >+ >+ public Object visit(final ASTValueSuffix node, final Object data) >+ { >+ final ValueExpressionTracker tracker = ((EvaluationTracker) data).getValueTracker(); >+ final SignatureBasedType type = ((EvaluationTracker) data).getType(); >+ >+ if (type instanceof IObjectSymbolBasedValueType) >+ { >+ final IObjectSymbolBasedValueType symbolType = >+ (IObjectSymbolBasedValueType) type; >+ final Token firstToken = node.getFirstToken(); >+ final Token lastToken = node.getLastToken(); >+ >+ >+ if (node.jjtGetNumChildren() == 0 >+ && firstToken.kind == JSPELParserConstants.DOT) >+ { >+ final int lastTokenOffset = calcTokenOffset(lastToken); >+ final int lastTokenLength = calcTokenLength(lastToken); >+ final DotOperator dotOp = new DotOperator(_diagnosticFactory, _targetFile); >+ >+ final StringLiteralType suffixLiteral = new StringLiteralType(lastToken.image); >+ OperationResult opResult = >+ dotOp.performOperation(symbolType, >+ suffixLiteral); >+ >+ if (opResult.diagnostic.getSeverity() != Diagnostic.OK) >+ { >+ addMessageFromDiagnostic(opResult.diagnostic, lastTokenOffset, lastTokenLength); >+ } >+// // if the base (value-a) is a map, then using the bracket value-a['y'] type >+// // syntax is recommended. Note that we do this here instead of >+// // DotOperator so that we don't tie the default property resolver >+// // behaviour to that operator class. If someone changes the rules >+// // of how the prop resolver interprets the base, then they may want to >+// // write their own validator that doesn't do this >+// if (symbolType.getSymbol().supportsCoercion(TypeConstants.TYPE_MAP)) >+// { >+// _messages.add(ValidationMessageFactory.createFromDiagnostic( >+// DiagnosticFactory.create_BINARY_OP_DOT_WITH_VALUEA_MAP_SHOULD_USE_ARRAY >+// (symbolType.getSymbol().getName(), dotId.image), >+// startOffset, length, _targetFile)); >+// } >+ >+ ((EvaluationTracker) data).setType(opResult.resultType); >+ updateValueTracker(tracker, node, symbolType, firstToken.image, opResult.resultType, lastTokenOffset, lastTokenLength); >+ >+ // we finished with the single dot suffix here >+ return data; >+ } >+ else if (firstToken.kind == JSPELParserConstants.LBRACKET) >+ { >+ final int suffixOffset = calcTokenOffset(firstToken); >+ final int suffixLength = lastToken.endColumn - firstToken.beginColumn + 1; >+ >+ final EvaluationTracker subExprTracker = new EvaluationTracker(); >+ node.childrenAccept(this, subExprTracker); >+ >+ final SignatureBasedType subExprType = subExprTracker.getType(); >+ >+ if (subExprType instanceof ValueType || subExprType == null) >+ { >+ final BracketOperator bracketOperator = new BracketOperator(_diagnosticFactory, _targetFile); >+ >+ final OperationResult opResult = >+ bracketOperator.performOperation(symbolType, >+ (ValueType)subExprType); >+ >+ if (opResult.diagnostic.getSeverity() != Diagnostic.OK) >+ { >+ addMessageFromDiagnostic(opResult.diagnostic, suffixOffset, suffixLength); >+ } >+ ((EvaluationTracker) data).setType(opResult.resultType); >+ updateValueTracker(tracker, node, symbolType, firstToken.image, opResult.resultType, suffixOffset, suffixLength); >+ } >+ // we are finished with the bracketed suffix at this point. >+ return data; >+ } >+ } >+ else if (type instanceof IMethodSymbolBasedType) >+ { >+ if (isValidate()) >+ { >+ final Token operatorToken = node.getFirstToken(); >+ int offset = calcTokenOffset(operatorToken); >+ int length = calcTokenLength(operatorToken); >+ Diagnostic diagnostic = _diagnosticFactory.create_CANNOT_APPLY_OPERATOR_TO_METHOD_BINDING(); >+ addMessageFromDiagnostic(diagnostic, offset, length); >+ } >+ } >+ >+ // don't bother to accept children, since if we haven't done >+ // something above, there's not much sensible we can do with it >+ // clear the type first though >+ ((EvaluationTracker) data).setType(null); >+ return data; //node.childrenAccept(this, data); >+ } >+ >+ private int calcTokenLength(final Token token) { >+ return token.endColumn - token.beginColumn + 1; >+ } >+ >+ private int calcTokenOffset(final Token token) { >+ return _context.getDocumentPosition() + token.beginColumn - 1; >+ } >+ >+ public Object visit(SimpleNode node, Object data) { >+ return node.childrenAccept(this, data); >+ } >+ >+ /**Overwrite this and {@link #isValidate()} if you want to collect validation messages. >+ * Default implementation does nothing. >+ * @param diagnostic >+ * @param offset >+ * @param length >+ */ >+ protected void addMessageFromDiagnostic(Diagnostic diagnostic, int offset, int length) { >+ // does nothing >+ } >+ >+ /** Called to update state while tracking an EL value. Overwrite this if you want to follow >+ * tracking of EL values or track additional info >+ * @param tracker - the ValueExpressionTracker used to track >+ * @param node - the current node >+ * @param parentType - the type of the expression before the current node. May be <code>null</code>. >+ * @param suffixOperator - the operator ("." or "[") that preceeds the current symbol. >+ * <code>null</code> if current symbol is no member symbol >+ * @param resultType - the type of the expression including the current node >+ * @param startOffset - the offset of the current node in document >+ * @param length - the length of the current node >+ */ >+ protected void updateValueTracker(final ValueExpressionTracker tracker, final SimpleNode node, >+ final IObjectSymbolBasedValueType parentType, final String suffixOperator, >+ final SignatureBasedType resultType, final int startOffset, final int length) { >+ tracker.setCurrentSymbolPos(startOffset, length); >+ tracker.setCurrentSuffixOperator(suffixOperator); >+ if (resultType instanceof IObjectSymbolBasedValueType) { >+ tracker.setCurrentSymbol(((IObjectSymbolBasedValueType) resultType).getSymbol()); >+ } else if (resultType instanceof IMethodSymbolBasedType) { >+ tracker.setCurrentSymbol(((IMethodSymbolBasedType) resultType).getSymbol()); >+ } else { >+ tracker.setCurrentSymbol(null); >+ } >+ if (parentType != null) { >+ tracker.setParentSymbol(parentType.getSymbol()); >+ } else { >+ tracker.setParentSymbol(null); >+ } >+ } >+ >+ private void performBinaryEvaluation(ASTOperatorExpression node, EvaluationTracker tracker) >+ { >+ if (node.jjtGetNumChildren() < 2) >+ { >+ throw new AssertionError("Binary operators should always have at least two sub-expressions"); //$NON-NLS-1$ >+ } >+ else if (node.getOperatorTokens().size() != node.jjtGetNumChildren()-1) >+ { >+ throw new AssertionError("Binary operators should always have one operator token less than number of sub-expressions"); //$NON-NLS-1$ >+ } >+ >+ // evaluate left-most argument >+ node.jjtGetChild(0).jjtAccept(this, tracker); >+ >+ ValueType curType = getValueTypeForBinaryOperation(tracker.getType(), (SimpleNode) node.jjtGetChild(0)); >+ >+ for (int child = 1; child < node.jjtGetNumChildren(); child++) >+ { >+ // evaluate next argument running left-to-right >+ node.jjtGetChild(child).jjtAccept(this, tracker); >+ final ValueType secondType = >+ getValueTypeForBinaryOperation(tracker.getType(), (SimpleNode) node.jjtGetChild(child)); >+ >+ if (curType != null && secondType != null) >+ { >+ final BinaryOperator operator = >+ BinaryOperator.getBinaryOperator((Token)node.getOperatorTokens().get(child-1), _diagnosticFactory, _context); //diagnosticFactory >+ >+ final Diagnostic diagnostic = operator.validate(curType, secondType); >+ >+ if (diagnostic.getSeverity() != Diagnostic.OK) >+ { >+ final Token firstToken = node.getFirstToken(); >+ final int offset = calcTokenOffset(firstToken); >+ final int length = node.getLastToken().endColumn - firstToken.beginColumn+1; >+ addMessageFromDiagnostic(diagnostic, offset, length); >+ } >+ >+ curType = operator.performOperation(curType, secondType); >+ } >+ } >+ >+ tracker.setType(curType); >+ } >+ >+ private ValueType getValueTypeForBinaryOperation(SignatureBasedType type, SimpleNode node) >+ { >+ if (type instanceof ValueType) >+ { >+ return (ValueType) type; >+ } >+ else if (type instanceof MethodType) >+ { >+ if (isValidate()) >+ { >+ final int offset = _context.getDocumentPosition() + node.getFirstToken().beginColumn - 1; >+ final int length = node.getLastToken().endColumn - node.getFirstToken().beginColumn+1; >+ >+ addMessageFromDiagnostic(_diagnosticFactory.create_CANNOT_APPLY_OPERATOR_TO_METHOD_BINDING(), offset, length); >+ } >+ } >+ >+ return null; >+ } >+ >+ private String stripQuotes(String stringLiteral) >+ { >+ if (stringLiteral.startsWith("'") //$NON-NLS-1$ >+ || stringLiteral.startsWith("\"")) //$NON-NLS-1$ >+ >+ { >+ if (stringLiteral.length() > 2) >+ { >+ // take 'literal' -> literal >+ return stringLiteral.substring(1, stringLiteral.length()-1); >+ } >+ // if only two characters, then the empty string >+ return ""; //$NON-NLS-1$ >+ } >+ >+ return stringLiteral; >+ } >+ >+ /**Decides whether validation messages should be created. Default implementation >+ * returns <code>false</code>. Overwrite this and {@link #addMessageFromDiagnostic(Diagnostic, int, int)} >+ * if you want to have valdiation messages created. >+ * @return true, if validation messages should be created >+ */ >+ protected boolean isValidate() { >+ return false; >+ } >+ >+ /** >+ * @return the ASTExpression to parse >+ */ >+ protected ASTExpression getExpr() { >+ return _expr; >+ } >+ >+ /** >+ * @return the IStructuredDocumentContext containing the expression >+ */ >+ protected IStructuredDocumentContext getContext() { >+ return _context; >+ } >+ >+ /** >+ * @return the EvaluationTracker used to track state while parsing the expression >+ */ >+ protected EvaluationTracker getTracker() { >+ return _tracker; >+ } >+ >+ /** >+ * @return the file containing the EL expression to be traversed. >+ */ >+ protected IFile getTargetFile() { >+ return _targetFile; >+ } >+ >+} >Index: src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolResolveUtil.java >=================================================================== >RCS file: src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolResolveUtil.java >diff -N src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolResolveUtil.java >--- /dev/null 1 Jan 1970 00:00:00 -0000 >+++ src/org/eclipse/jst/jsf/core/internal/contentassist/el/SymbolResolveUtil.java 1 Jan 1970 00:00:00 -0000 >@@ -0,0 +1,143 @@ >+package org.eclipse.jst.jsf.core.internal.contentassist.el; >+ >+import java.util.Arrays; >+import java.util.Iterator; >+import java.util.List; >+ >+import org.eclipse.jst.jsf.common.internal.types.CompositeType; >+import org.eclipse.jst.jsf.common.internal.types.IAssignable; >+import org.eclipse.jst.jsf.context.resolver.structureddocument.IDOMContextResolver; >+import org.eclipse.jst.jsf.context.resolver.structureddocument.IStructuredDocumentContextResolverFactory; >+import org.eclipse.jst.jsf.context.resolver.structureddocument.ITaglibContextResolver; >+import org.eclipse.jst.jsf.context.structureddocument.IStructuredDocumentContext; >+import org.eclipse.jst.jsf.context.symbol.IInstanceSymbol; >+import org.eclipse.jst.jsf.context.symbol.IObjectSymbol; >+import org.eclipse.jst.jsf.context.symbol.ISymbol; >+import org.eclipse.jst.jsf.designtime.resolver.ISymbolContextResolver; >+import org.eclipse.jst.jsf.designtime.resolver.StructuredDocumentSymbolResolverFactory; >+import org.eclipse.jst.jsf.metadataprocessors.MetaDataEnabledProcessingFactory; >+import org.eclipse.jst.jsf.metadataprocessors.features.ELIsNotValidException; >+import org.eclipse.jst.jsf.metadataprocessors.features.IValidELValues; >+import org.w3c.dom.Attr; >+import org.w3c.dom.Element; >+import org.w3c.dom.Node; >+ >+/** >+ * Utility class for resolving symbols for a IStructuredDocumentContext. >+ */ >+public class SymbolResolveUtil { >+ >+ private SymbolResolveUtil() { >+ // utility class; not instantiable >+ } >+ >+ /** Get symbol for a variable (managed bean name, bundle name) >+ * @param context >+ * @param name >+ * @return ISymbol >+ */ >+ public static ISymbol getSymbolForVariable(IStructuredDocumentContext context, String name) { >+ final ISymbolContextResolver symbolResolver = StructuredDocumentSymbolResolverFactory.getInstance() >+ .getSymbolContextResolver(context); >+ >+ return symbolResolver.getVariable(name); >+ } >+ >+ /**Get symbol for a variable suffix (e. g. bean property/method, bundle property). Takes into account >+ * whether method bindings are expected for the given context. >+ * @param context - the IStructuredDocumentContext >+ * @param fullName - full name of the suffix (e. g. bean.property1.property2) >+ * @param isLastSuffix - set true if there follows no other suffix. Method names will only be considered if true >+ * @return ISymbol. May be null. >+ */ >+ public static ISymbol getSymbolForVariableSuffixExpr(IStructuredDocumentContext context, String fullName, boolean isLastSuffix) { >+ String[] ids = fullName.split("\\."); //$NON-NLS-1$ >+ >+ // if no suffixes, only one id >+ if (ids.length < 1) { >+ ids = new String[] { fullName }; >+ } >+ >+ final ISymbolContextResolver symbolResolver = StructuredDocumentSymbolResolverFactory.getInstance() >+ .getSymbolContextResolver(context); >+ if (symbolResolver != null) { >+ ISymbol symbol = symbolResolver.getVariable(ids[0]); >+ if (symbol != null && symbol instanceof IInstanceSymbol && ((IInstanceSymbol) symbol).isTypeResolved()) { >+ for (int curSuffixIdx = 1; curSuffixIdx < ids.length; curSuffixIdx++) { >+ if (isLastSuffix && curSuffixIdx == ids.length - 1 && isMethodBindingExpected(context)) { >+ /* TODO Take into account required method signature, since there may be different >+ * methods with the same name */ >+ return symbolResolver.getMethod((IObjectSymbol) symbol, ids[curSuffixIdx]); >+ } >+ final ISymbol property = symbolResolver.getProperty(symbol, ids[curSuffixIdx]); >+ if (property == null) { >+ return null; >+ } >+ symbol = property; >+ } >+ return symbol; >+ } >+ } >+ return null; >+ } >+ >+ /**Tells whether method bindings are expected for the given context. >+ * @param context - the IStructuredDocumentContext >+ * @return true, if method bindings expected >+ */ >+ public static boolean isMethodBindingExpected(IStructuredDocumentContext context) { >+ return isMethodBindingExpected(context, null); >+ } >+ >+ /**Tells whether method bindings are expected for the given context. Will add signatures of expected >+ * method bindings to a given list. >+ * @param context - the IStructuredDocumentContext >+ * @param expectedBindings - a list. If not null, signatures of expected method bindings will be appended to this list. >+ * @return true, if method bindings expected >+ */ >+ public static boolean isMethodBindingExpected(IStructuredDocumentContext context, List expectedBindings) { >+ final IDOMContextResolver domResolver = IStructuredDocumentContextResolverFactory.INSTANCE >+ .getDOMContextResolver(context); >+ >+ final Node curNode = domResolver.getNode(); >+ >+ if (curNode instanceof Attr) { >+ final Attr attr = (Attr) curNode; >+ final Element element = attr.getOwnerElement(); >+ >+ final ITaglibContextResolver taglibResolver = IStructuredDocumentContextResolverFactory.INSTANCE >+ .getTaglibContextResolver(context); >+ >+ final String uri = taglibResolver.getTagURIForNodeName(element); >+ >+ final List elVals = MetaDataEnabledProcessingFactory.getInstance() >+ .getAttributeValueRuntimeTypeFeatureProcessors(IValidELValues.class, context, uri, >+ element.getLocalName(), attr.getLocalName()); >+ >+ boolean methodBindingExpected = false; >+ for (final Iterator it = elVals.iterator(); it.hasNext();) { >+ final IValidELValues validValues = (IValidELValues) it.next(); >+ >+ try { >+ CompositeType type = validValues.getExpectedRuntimeType(); >+ if (type != null && type.getAssignmentTypeMask() == IAssignable.ASSIGNMENT_TYPE_NONE) { >+ methodBindingExpected = true; >+ if (expectedBindings != null) { >+ expectedBindings >+ .addAll(Arrays.asList(validValues.getExpectedRuntimeType().getSignatures())); >+ } else { >+ // if we don't need the method signatures, *one* expected method binding is sufficient. >+ return true; >+ } >+ } >+ } catch (ELIsNotValidException e) { >+ // do nothing >+ } >+ } >+ return methodBindingExpected; >+ } >+ // default condition is no method binding >+ return false; >+ } >+ >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 199853
:
76035
| 83328