001    /*
002     * mesopotamia @mesopotamia.version@
003     * Multilingual parser and repository. 
004     * Copyright (C) 2005  Hammurapi Group
005     *
006     * This program is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 2 of the License, or (at your option) any later version.
010     *
011     * This program is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with this library; if not, write to the Free Software
018     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
019     *
020     * URL: http://http://www.hammurapi.biz
021     * e-Mail: support@hammurapi.biz
022     */
023    package org.mesopotamia;
024    
025    import java.awt.event.WindowEvent;
026    import java.io.StringReader;
027    import java.lang.reflect.Method;
028    import java.util.ArrayList;
029    import java.util.Collections;
030    import java.util.Iterator;
031    import java.util.List;
032    
033    import javax.swing.WindowConstants;
034    import javax.swing.tree.TreeNode;
035    
036    import org.mesopotamia.util.BnfLexer;
037    import org.mesopotamia.util.BnfRecognizer;
038    import org.mesopotamia.util.BnfTokenTypes;
039    import org.mesopotamia.util.UnmodifiableConvertingList;
040    import org.w3c.dom.Element;
041    
042    import antlr.RecognitionException;
043    import antlr.TokenStreamException;
044    import antlr.collections.AST;
045    import biz.hammurapi.convert.ConverterClosure;
046    import biz.hammurapi.convert.ConvertingService;
047    import biz.hammurapi.legacy.review.Signed;
048    import biz.hammurapi.swing.Browser;
049    import biz.hammurapi.swing.Visualizable;
050    import biz.hammurapi.util.VisitableBase;
051    import biz.hammurapi.xml.dom.DomSerializable;
052    
053    /**
054     * Generic wrapper for AST. 
055     * More sophisticated classes (e.g. try block representation)
056     * shall extend this class.
057     * @author Pavel Vlasov
058     * @revision $Revision: 1.2 $
059     */
060    public class LanguageElement extends VisitableBase implements DomSerializable, Signed, Comparable<LanguageElement> {
061            
062            private Scan scan;
063            private NodeData xData;
064            private RepositoryLanguage language;
065            protected Object environment;
066            private LanguageElementHandle handle;
067    
068            /**
069             * Instances of LanguageElement shall be created only by
070             * repository
071             */
072            protected LanguageElement(NodeData xData, Class<?> context, Scan scan, RepositoryLanguage language, Object environment) {
073                    this.scan=scan;
074                    try {
075                            this.xData=(NodeData) xData.clone();
076                    } catch (CloneNotSupportedException e) {
077                            throw new MesopotamiaRuntimeException(e);
078                    }
079                    if (xData instanceof MesopotamiaNode && ((MesopotamiaNode) xData).getParent()!=null) {
080                            this.setParentHandle(new LanguageElementHandle(xData.getSourceUnitId(), ((MesopotamiaNode) xData).getParent().getId(), null, null)); 
081                    }
082                    this.language=language;
083                    this.environment=environment;
084                    this.handle=new LanguageElementHandle(xData.getSourceUnitId(), xData.getId(), context, getClass());             
085            }
086            
087            private LanguageElementHandle parentHandle;
088            
089            public void setParentHandle(LanguageElementHandle parentHandle) {
090                    if (parentHandle!=null) {
091                            if (parentHandle.getId()==xData.getId()) {
092                                    throw new IllegalArgumentException("Self parent");
093                            }
094                            if (parentHandle.getSourceUnitId()!=xData.getSourceUnitId()) {                          
095                                    throw new IllegalArgumentException("Parent from different source unit, this "+xData+", parent "+parentHandle);
096                            }
097                    }
098    
099                    this.parentHandle = parentHandle;
100            }
101            
102            public LanguageElement getParent() {
103                    return parentHandle==null ?  null : scan.getLanguageElement(parentHandle);
104            }
105            
106            public RepositoryLanguage getLanguage() {
107                    return language;
108            }
109            
110            public int getType() {
111                    return language.tokenTypeId2type(xData.getType());
112            }
113            
114            private List<Object> childrenData; // Collection of NodeData
115            private List<Object> children;
116            
117            /**
118             * Language element should not keep references to children, but a 
119             * collection of children's primary keys (java.lang.Integer) and 
120             * use converting collection (biz.hammurapi.util.ConvertingCollection),
121             * which would use Repository's languageElementCache to look up child instance.
122             * @return
123             * @throws MesopotamiaException 
124             */
125            public synchronized List<Object> getChildren() throws MesopotamiaException {
126                    if (childrenData==null) {
127                            childrenData = new ArrayList<Object>();
128                            Iterator<MesopotamiaNode> it = getNode().getChildren().iterator();                                
129                            while (it.hasNext()) {
130                                    try {
131                                            childrenData.add(it.next().clone());
132                                    } catch (CloneNotSupportedException e) {
133                                            throw new MesopotamiaRuntimeException(e);
134                                    } 
135                            }
136                            
137                            children=new UnmodifiableConvertingList<Object>(childrenData,data2leConverter); 
138                    }
139                    return children;
140            }
141    
142            public MesopotamiaNode getNode() {
143                    return getSourceUnit().getSyntaxTree().findNode(xData.getId());
144            }
145            
146            /**
147             * Convenience method
148             * @param idx
149             * @return
150             * @throws MesopotamiaException 
151             */
152            public LanguageElement getChild(int idx) throws MesopotamiaException {
153                    List<Object> ch = getChildren();
154                    return ch.size()>idx ? (LanguageElement) ch.get(idx) : null;
155            }
156            
157            /**
158             * Convenience method
159             * @param idx
160             * @return
161             * @throws MesopotamiaException 
162             */
163            public int getChildId(int idx) throws MesopotamiaException {
164                    return getChildren().size()>idx ? ((NodeData) childrenData.get(idx)).getId() : 0;
165            }
166            
167            protected ConverterClosure data2leConverter=new ConverterClosure() {
168    
169                    public Object convert(Object source) {
170                            NodeData nd = (NodeData) source;
171                            LanguageElementHandle childHandle = new LanguageElementHandle(nd.getSourceUnitId(), nd.getId(), LanguageElement.this.getClass(), null);
172                            LanguageElement child = scan.getLanguageElement(childHandle);
173                            child.setParentHandle(LanguageElement.this.handle);
174                            return child;
175                    }
176                    
177            };
178            
179            protected ConverterClosure le2idConverter=new ConverterClosure() {
180    
181                    public Object convert(Object source) {
182                            return new Integer(((LanguageElement) source).getId());
183                    }
184                    
185            };
186            
187            public LanguageElement getPrevSibling() {
188                    return getSibling(-1);
189            }
190    
191            public LanguageElement getNextSibling() {
192                    return getSibling(+1);
193            }
194            
195            public LanguageElement getSibling(int offset) {
196                    SyntaxTree st = getSourceUnit().getSyntaxTree();
197                    List<MesopotamiaNode> siblings = parentHandle==null ? st.getRoots() : st.findNode(parentHandle.getId()).getChildren();
198                    int idx = xData.getPosition()+offset;
199                    if (idx<0 || idx>=siblings.size()) {
200                            return null;
201                    }
202                    NodeData sibling = siblings.get(idx);           
203                    if (sibling==null) {
204                            return null;
205                    }
206                    LanguageElement parent=getParent();
207                    LanguageElementHandle siblingHandle=new LanguageElementHandle(
208                                    xData.getSourceUnitId(),
209                                    sibling.getId(),
210                                    parent==null ? null : getParent().getClass(),
211                                    null);
212                    return scan.getLanguageElement(siblingHandle);
213            }
214    
215    //      public Long getChecksum() {
216    //              return dbData.getChecksum();
217    //      }
218    
219            public int getCol() {
220                    return xData.getColumn();
221            }
222    
223    //      public Token getFirstToken() {
224    //              return xData.getFirstTokenId()==null ? null : getSourceUnit().getToken(dbData.getFirstTokenId().intValue());
225    //      }
226    
227            public int getId() {
228                    return xData.getId();
229            }
230    
231    //      public Token getLastToken() {
232    //              return dbData.getLastTokenId()==null ? null : getSourceUnit().getToken(dbData.getLastTokenId().intValue());
233    //      }
234    //      
235    //      public Token getToken() {
236    //              return dbData.getTokenId()==null ? null : getSourceUnit().getToken(dbData.getTokenId().intValue());
237    //      }
238    
239            public int getLine() {
240                    return xData.getLine();
241            }
242    
243            /**
244             * Change to lazy calculation once in the future.
245             * @return
246             */
247            public String getSignature() {
248                    StringBuffer ret=new StringBuffer();
249                    LanguageElement parent = getParent();
250                    if (parent==this) {
251                            /*
252                             * There might be cases where signature is not applicable. 
253                             * We use element ID and location in this case. This signature is not as good as
254                             * regular signature, but there is no better way.
255                             */                     
256                            return getSourceUnit().getPath()+":ID:"+getId(); 
257                    }
258                    if (parent==null) {
259                            ret.append(getSourceUnit().getPath());
260                    } else {
261                            ret.append(parent.getSignature());
262                    }
263                    ret.append(":");
264                    ret.append(language.tokenTypeId2name(xData.getType()));
265    //              if (xData.getSignatureId()!=null) {
266    //                      ret.append("[");
267    //                      ret.append(getText(dbData.getSignatureId()));
268    //                      ret.append("]");
269    //              } else {
270                            if (xData.getSameTypeIndex()!=0) {
271                                    ret.append("[");
272                                    ret.append(xData.getSameTypeIndex());
273                                    ret.append("]");
274                            }
275    //              }
276                    return ret.toString();
277            }
278    
279    //      /**
280    //       * Retrieves text from string storage
281    //       * @return
282    //       */
283    //      protected String getText(Integer id) {          
284    //              return scan.getRepository().getFactory().getStringStorage().getText(id);
285    //      }
286    
287            public AstSourceUnit getSourceUnit() {
288                    return (AstSourceUnit) scan.getSourceUnit(xData.getSourceUnitId());
289            }
290    
291            /**
292             * @return Language element text
293             */
294            public String getText() {
295                    return xData.getText(); //getText(dbData.getTextId());
296            }
297    
298    //      public Token getToken() throws MesopotamiaException {
299    //              // It would be too cumbersome to keep tokens in memory cache - instantiate them
300    //              // directly. It can be changed in the future anyway.
301    //              if (dbData.getTokenId()==null) {
302    //                      return null;
303    //              }
304    //              
305    //              try {
306    //                      return new Token(getSourceUnit(), repository.getFactory().getEngine().getToken(dbData.getSourceUnitId(), dbData.getTokenId().intValue()));
307    //              } catch (SQLException e) {
308    //                      throw new MesopotamiaException(e);
309    //              } 
310    //      }
311    
312    //      public int getSize() {
313    //              return dbData.getTotalSize();
314    //      }
315    
316            public void toDom(Element holder) {
317                    holder.setAttribute("id",String.valueOf(xData.getId()));
318                    holder.setAttribute("column",String.valueOf(xData.getColumn()));
319                    holder.setAttribute("line",String.valueOf(xData.getLine()));
320                    holder.setAttribute("token-type",language.tokenTypeId2name(xData.getType()));
321                    holder.setAttribute("class",getClass().getName());
322                    setAttribute(holder, "text",getText());
323    //              Token token = getToken();
324    //              if (token!=null) {
325    //                      holder.setAttribute("token-position", String.valueOf(token.getPosition()));
326    //              }
327            }
328    
329            /**
330             * Token name, e.g. METHOD_CALL
331             * @return
332             */
333            public String getTokenName() {
334                    return language.tokenTypeId2name(xData.getType());
335            }       
336            
337    //      protected org.mesopotamia.sql.LanguageElement[] getDbChildrenByType(int type) throws MesopotamiaException {             
338    //              getChildren();
339    //              Collection ret=new ArrayList();
340    //              Iterator it=childrenIds.iterator();
341    //              int typeId=language.tokenType2id(type);
342    //              while (it.hasNext()) {
343    //                      org.mesopotamia.MesopotamiaNodedbLe=(org.mesopotamia.sql.LanguageElement) it.next();
344    //                      if (dbLe.getTokenTypeId()==typeId) {
345    //                              ret.add(dbLe);
346    //                      }
347    //              }
348    //              return (org.mesopotamia.sql.LanguageElement[]) ret.toArray(new org.mesopotamia.sql.LanguageElement[ret.size()]);
349    //      }
350            
351            protected Scan getScan() {
352                    return scan;
353            }
354            
355            /**
356             * Selects collection of language elements based on path expression.
357             * @param context
358             * @param path
359             * @return List of language elements
360             */
361            public <T> UnmodifiableConvertingList<T> select(final Class<T> targetClass, String path) throws MesopotamiaException {
362                    try {
363                            StringReader sr=new StringReader(path);
364                            BnfLexer lexer=new BnfLexer(sr);
365                            BnfRecognizer parser=new BnfRecognizer(lexer);
366                            parser.standaloneIndexedPath();
367                            List<NodeData> results=new ArrayList<NodeData>();
368                            //System.out.println("=== Selecting: "+path);
369                            //AstUtil.dump(parser.getAST(), parser.getTokenNames());
370                            for (AST pe=parser.getAST(); pe!=null; pe=pe.getNextSibling()) {
371                                    List<NodeData> peResults=new ArrayList<NodeData>();
372                                    peResults.add(xData);
373                                    for (AST node=pe.getFirstChild(); node!=null; node=node.getNextSibling()) {
374                                            peResults=processNode(peResults, node.getFirstChild());
375                                    }
376                                    results.addAll(peResults);
377                            }
378                            
379                            return new UnmodifiableConvertingList<T>(
380                                            results,
381                                            new ConverterClosure() {
382    
383                                                    public Object convert(Object source) {
384                                                            NodeData nd = (NodeData) source;
385                                                            LanguageElementHandle handle = new LanguageElementHandle(nd.getSourceUnitId(), nd.getId(), LanguageElement.this.getClass(), targetClass);
386                                                            LanguageElement selectedChild = scan.getLanguageElement(handle);
387                                                            selectedChild.setParentHandle(LanguageElement.this.handle);
388                                                            return selectedChild;
389                                                    }
390                                                    
391                                            });
392    
393                    } catch (RecognitionException e) {
394                            throw new MesopotamiaException("Cannot parse path: "+path, e);
395                    } catch (TokenStreamException e) {
396                            throw new MesopotamiaException("Cannot parse path: "+path, e);
397                    } catch (ClassNotFoundException e) {
398                            throw new MesopotamiaException("Cannot process selection from path: "+path, e);
399                    }
400            }
401            
402            private List<NodeData> processNode(List<NodeData> input, AST node) throws MesopotamiaException, ClassNotFoundException {
403                    //System.out.println("--- Processing: "+BnfRecognizer._tokenNames[node.getType()]);
404                    SyntaxTree st = getSourceUnit().getSyntaxTree();
405                    List<NodeData> ret=new ArrayList<NodeData>();
406                    Iterator<NodeData> it=input.iterator();
407                    while (it.hasNext()) {
408                            List<NodeData> receiver=new ArrayList<NodeData>();
409                            MesopotamiaNode contextNode = st.findNode(it.next().getId());
410                            switch (node.getType()) {
411                            case BnfTokenTypes.IDENT: {
412                                    Iterator<MesopotamiaNode> cit = contextNode.getChildren().iterator();
413                                    while (cit.hasNext()) {
414                                            NodeData cnd = cit.next();
415                                            checkSameSourceUnit(cnd);
416                                            if (cnd.getType()==language.tokenName2id(node.getText())) {
417                                                    receiver.add(cnd);
418                                            }
419                                    }
420                                    break;
421                            }
422                            case BnfTokenTypes.EXCL: {
423                                    Iterator<MesopotamiaNode> cit = contextNode.getChildren().iterator();
424                                    while (cit.hasNext()) {
425                                            NodeData cnd = cit.next();
426                                            checkSameSourceUnit(cnd);
427                                            if (cnd.getType()!=language.tokenName2id(node.getFirstChild().getText())) {
428                                                    receiver.add(cnd);
429                                            }
430                                    }
431                                    break;
432                            }
433                            case BnfTokenTypes.STAR:
434                                    receiver.addAll(contextNode.getChildren());
435                                    break;
436                            case BnfTokenTypes.DOUBLEDOT:
437                                    throw new UnsupportedOperationException("Not yet implemented");
438                            case BnfTokenTypes.TYPE_REF:
439                                    StringBuffer typeName=new StringBuffer();
440                                    typeName(node.getFirstChild(), typeName);
441                                    Class<?> type=language.getClassLoader().loadClass(typeName.toString());
442                                    Iterator<MesopotamiaNode> lit=contextNode.getChildren().iterator();
443                                    while (lit.hasNext()) {
444                                            NodeData cnd = lit.next();
445                                            checkSameSourceUnit(cnd);
446                                            LanguageElement cle=scan.getLanguageElement(new LanguageElementHandle(cnd.getSourceUnitId(), cnd.getId(), this.getClass(), null));
447                                            if (type.isInstance(cle)) {
448                                                    receiver.add(cnd);
449                                            }
450                                    }
451                                    
452                                    break;
453                            default:
454                                    throw new MesopotamiaException("Unexpected node type: "+BnfRecognizer._tokenNames[node.getType()]);                                     
455                            }
456                            
457                            if (node.getNextSibling()!=null) {
458                                    int idx=Integer.parseInt(node.getNextSibling().getFirstChild().getText());
459                                    if (idx>=0 && idx<receiver.size()) {
460                                            ret.add(receiver.get(idx));
461                                    }
462                            } else {
463                                    ret.addAll(receiver);
464                            }
465                    }
466                    return ret;
467            }
468            
469            private void checkSameSourceUnit(NodeData cnd) {
470                    if (cnd.getSourceUnitId()!=xData.getSourceUnitId()) {
471                            throw new IllegalStateException("Nodes from different source units: "+xData+", "+cnd);
472                    }
473                    
474            }
475    
476            static void typeName(AST node, StringBuffer sb) {
477                    if (node.getType()==BnfTokenTypes.DOT) {
478                            typeName(node.getFirstChild(), sb);
479                            sb.append(".");
480                            typeName(node.getFirstChild().getNextSibling(), sb);
481                    } else {
482                            sb.append(node.getText());
483                    }
484            }
485            
486            /**
487             * Selects single language element handle based on path expression
488             * @param context
489             * @param path
490             * @return
491             * @throws MesopotamiaException 
492             */
493            public LanguageElementHandle selectSingleElementHandle(Class targetClass, String path) throws MesopotamiaException {
494                    UnmodifiableConvertingList<LanguageElement> c=select(targetClass, path);
495                    if (c.isEmpty()) {
496                            return null;
497                    }
498                    NodeData nd = (NodeData) c.getMaster().get(0);
499                    return new LanguageElementHandle(nd.getSourceUnitId(), nd.getId(), getClass(), targetClass);            
500            }
501            
502            /**
503             * Selects single language element based on path expression
504             * @param context
505             * @param path
506             * @return
507             * @throws MesopotamiaException 
508             */
509            public <T> T selectSingleElement(Class<T> targetClass, String path) throws MesopotamiaException {
510                    List<T> c=select(targetClass, path);
511                    return (T) (c.isEmpty() ? null : c.get(0));             
512            }
513            
514            public <T> String selectSingleElementText(Class<T> targetClass, String path) throws MesopotamiaException {
515                    T le=selectSingleElement(targetClass, path);
516                    return le instanceof LanguageElement ? ((LanguageElement) le).getText() : null;
517            }
518            
519            public List<String> selectText(Class targetClass, String path) throws MesopotamiaException {
520                    List<String> ret=new ArrayList<String>();
521                    Iterator<LanguageElement> it=select(targetClass, path).iterator();
522                    while (it.hasNext()) {
523                            ret.add(it.next().getText());
524                    }
525                    return ret;
526            }       
527            
528            /**
529             * Sets attribute if value is not null.
530             * @param holder
531             * @param name
532             * @param value
533             */
534            protected void setAttribute(Element holder, String name, String value) {
535                    if (value!=null) {
536                            holder.setAttribute(name, value);
537                    }
538            }
539            
540            /**
541             * Adds nested element if value is not null
542             * @param holder
543             * @param name
544             * @param value
545             */
546            protected void setElement(Element holder, String name, Object value) {
547                    if (value!=null) {
548                            Element el=holder.getOwnerDocument().createElement(name);
549                            holder.appendChild(el);
550                            DomSerializable ds = (DomSerializable) ConvertingService.convert(value, DomSerializable.class);
551                            ds.toDom(el);
552                    }
553            }
554            
555            /**
556             * Creates a converting list of language elements. Use this method to construct
557             * custom lists of language element children.
558             * @param idList
559             * @param targetType
560             * @return
561             */
562            protected List<LanguageElement> createLanguageElementsList(List<Object> nodeDataList, final Class targetType) {
563                    return new UnmodifiableConvertingList<LanguageElement>(
564                                    nodeDataList,
565                                    new ConverterClosure() {
566    
567                                            public Object convert(Object source) {
568                                                    NodeData nd = (NodeData) source;                                                
569                                                    LanguageElementHandle leHandle = new LanguageElementHandle(
570                                                                    nd.getSourceUnitId(), 
571                                                                    nd.getId(), 
572                                                                    LanguageElement.this.getClass(), 
573                                                                    targetType);
574                                                    
575                                                    LanguageElement ret = getScan().getLanguageElement(leHandle);
576                                                    ret.setParentHandle(handle);
577                                                    return ret;
578                                            }
579                            
580                    });
581            }
582            
583            /**
584             * @return Language element handle.
585             */
586            public LanguageElementHandle getHandle() {
587                    return handle;
588            }
589    
590            /**
591             * For sorting.
592             */
593            public int compareTo(LanguageElement otherElement) {
594                    int pathComparison=getSourceUnit().getPath().compareTo(otherElement.getSourceUnit().getPath());
595                    if (pathComparison==0) {
596                            int lineComparison=getLine()-otherElement.getLine();
597                            if (lineComparison==0) {
598                                    return getCol()-otherElement.getCol();
599                            }
600                            return lineComparison;
601                    }
602                    return pathComparison;
603            }
604            
605            public String getLocation() {
606                    return getSourceUnit().getPath()+" "+getLine()+":"+getCol();
607            }
608            
609            public String toString() {
610                    return "["+getClass().getName()+"] "+getTokenName()+" '"+getText()+"' "+getLocation();
611            }
612            
613            // Empty list to initialize list attributes
614            @SuppressWarnings("unchecked")
615            protected static final UnmodifiableConvertingList emptyList=
616                    new UnmodifiableConvertingList(Collections.unmodifiableList(new ArrayList()), null);
617            
618            /**
619             * Shows element in browser. Use it for debugging.
620             */
621            public void show() {
622                    Visualizable vs = (Visualizable) ConvertingService.convert(this, Visualizable.class); 
623                    String nName = getClass().getName();
624                    int idx = nName.lastIndexOf(".");
625                    String cName = idx==-1 ? nName : nName.substring(idx+1);
626                    TreeNode root = vs.toTreeNode(null, cName);
627                    
628                    final Object monitor = new Object();
629                    
630                    Browser browser = new Browser(cName+" "+getId()+" at "+getLocation(), root) {
631                            
632                            protected void processWindowEvent(WindowEvent e) {
633                                    super.processWindowEvent(e);
634                                    if (e.getID()==WindowEvent.WINDOW_CLOSED) {
635                                            synchronized (monitor) {
636                                                    monitor.notifyAll();
637                                            }
638                                    }
639                            }
640                    };
641                    
642                    browser.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
643                    browser.setVisible(true);
644                    
645                    synchronized (monitor) {
646                            try {
647                                    monitor.wait();
648                            } catch (InterruptedException ex) {
649                                    // Ignore
650                            }
651                    }
652            }
653            
654            /**
655             * Navigates up the tree looking for parent of particular type.
656             * @param clazz Type of parent to be found.
657             * @return Parent of type specified in <code>clazz</code> parameter.
658             */
659            @SuppressWarnings("unchecked")
660            public <T> T findParent(Class<T> clazz) {
661                    LanguageElement parent = getParent();
662    
663                    if (clazz.isInstance(parent) && parent != this && parent.getId()!=this.getId()) {
664                            return (T) parent;
665                    }
666    
667                    if (parent!=null && parent != this && parent.getId()!=this.getId()) {
668                            LanguageElement ret = (LanguageElement) parent.findParent(clazz);
669                            if (ret!=null) {
670                                    return (T) ret;
671                            }
672                    }
673    
674                    // Finding using syntax tree
675                    for (MesopotamiaNode parentNode = getNode().getParent(); parentNode!=null && parentNode.getParent()!=parentNode; parentNode = parentNode.getParent()) {
676                            LanguageElementHandle lh=new LanguageElementHandle(parentNode.getSourceUnitId(), parentNode.getId(), null, null);
677                            LanguageElement pe = scan.getLanguageElement(lh);
678                            if (clazz.isInstance(pe) && pe != this && pe.getId()!=this.getId()) {
679                                    return (T) pe;
680                            }
681                    }
682                    return null;
683            }
684            
685            /**
686             * Override it to return false for methods which shall not be 
687             * mounted to visualizer tree, i.e. methods which return references 
688             * to other language elements. 
689             * @return true if method return value shall be shown in the visualizer tree.
690             */
691            public boolean showInTree(Method method) {
692                    return method!=null && !method.getDeclaringClass().equals(LanguageElement.class) && LanguageElement.class.isAssignableFrom(method.getDeclaringClass());
693            }
694            
695    }