001    // This file is part of the RECODER library and protected by the LGPL.
002    
003    package recoder.abstraction;
004    
005    import recoder.NamedModelElement;
006    import recoder.bytecode.AccessFlags;
007    import recoder.convenience.Format;
008    import recoder.service.ProgramModelInfo;
009    import recoder.util.Order;
010    
011    /**
012     * An entity of the program meta model.
013     * 
014     * @author AL
015     * @author RN
016     */
017    public interface ProgramModelElement extends NamedModelElement, AccessFlags {
018    
019        /**
020         * Returns the maximal expanded name including all applicable qualifiers.
021         * 
022         * @return the full name of this program model element.
023         */
024        String getFullName();
025        
026        /**
027         * Returns the <i>binary</i> name. The binary name
028         * is the name this program model element would have in bytecode, i.e.,
029         * how it either is read by the bytecode parser, or the name a compiler
030         * would give this element during the compilation process (if this program
031         * model element is represented in source code). 
032         * See JLS, §13.1
033         * @since 0.92
034         * <!--@param useSlashes if <code>true</code>, slashes are used instead of dots in 
035         * the result, e.g., java/lang/Object instead of java.lang.Object.--> 
036         * @return the bytecode name of this program model element
037         */
038        String getBinaryName();
039    
040        /**
041         * Returns the instance that can retrieve information about this program
042         * model element.
043         * 
044         * @return the program model info of this element.
045         */
046        ProgramModelInfo getProgramModelInfo();
047    
048        /**
049         * Sets the instance that can retrieve information about this program model
050         * element. Should not be called from outside a service.
051         * 
052         * @param pmi
053         *            the program model info to be used for this element.
054         */
055        void setProgramModelInfo(ProgramModelInfo pmi);
056    
057        /**
058         * Lexical order objects comparing full names. For partial names, use the
059         * corresponding order of {@link recoder.NamedModelElement}.
060         */
061        Order LEXICAL_ORDER = new LexicalOrder();
062    
063        /**
064         * Lexical order on full names of program model elements. For partial names,
065         * use the corresponding order of {@link recoder.NamedModelElement}. Null
066         * elements are considered as empty strings. Program elements are kept
067         * unambiguous by attaching source code file name and positions.
068         */
069        class LexicalOrder implements Order {
070            public final int hashCode(Object x) {
071                if (x == null) {
072                    return 0;
073                }
074                String name = Format.toString("%N|%p|%u", (ProgramModelElement) x);
075                if (name == null) {
076                    return 0;
077                }
078                return name.hashCode();
079            }
080    
081            @SuppressWarnings("all") public final boolean isComparable(Object x, Object y) {
082                return true;
083            }
084    
085            private int diff(ProgramModelElement n1, ProgramModelElement n2) {
086                if (n1 == n2) {
087                    return 0;
088                }
089                String s1 = (n1 == null) ? "" : Format.toString("%N", n1);
090                String s2 = (n2 == null) ? "" : Format.toString("%N", n2);
091                int res = diff(s1, s2);
092                if (res == 0) {
093                    s1 = Format.toString("%p|%u", n1);
094                    s2 = Format.toString("%p|%u", n2);
095                    res = diff(s1, s2);
096                }
097                return res;
098            }
099    
100            private int diff(String s1, String s2) {
101                if (s1 == null) {
102                    s1 = "";
103                }
104                if (s2 == null) {
105                    s2 = "";
106                }
107                int len1 = s1.length();
108                int len2 = s2.length();
109                for (int i = 0, m = Math.min(len1, len2); i < m; i++) {
110                    char c1 = s1.charAt(i);
111                    char c2 = s2.charAt(i);
112                    if (c1 != c2) {
113                        return c1 - c2;
114                    }
115                }
116                return len1 - len2;
117            }
118    
119            public final boolean equals(Object x, Object y) {
120                return diff((ProgramModelElement) x, (ProgramModelElement) y) == 0;
121            }
122    
123            public final boolean less(Object x, Object y) {
124                return diff((ProgramModelElement) x, (ProgramModelElement) y) < 0;
125            }
126    
127            public final boolean greater(Object x, Object y) {
128                return diff((ProgramModelElement) x, (ProgramModelElement) y) > 0;
129            }
130    
131            public final boolean lessOrEquals(Object x, Object y) {
132                return diff((ProgramModelElement) x, (ProgramModelElement) y) <= 0;
133            }
134    
135            public final boolean greaterOrEquals(Object x, Object y) {
136                return diff((ProgramModelElement) x, (ProgramModelElement) y) >= 0;
137            }
138        }
139    }