IDLNames.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26/*
27 * Licensed Materials - Property of IBM
28 * RMI-IIOP v1.0
29 * Copyright IBM Corp. 1998 1999  All Rights Reserved
30 *
31 */
32
33package sun.rmi.rmic.iiop;
34
35import java.util.Hashtable;
36import java.util.Locale;
37import sun.tools.java.Identifier;
38import sun.tools.java.CompilerError;
39import sun.tools.java.ClassDefinition;
40import sun.tools.java.ClassNotFound;
41import com.sun.corba.se.impl.util.RepositoryId;
42
43/**
44 * IDLNames provides static utility methods to perform the IDL
45 * name mappings specified in Chapter 5 of the Java Language
46 * to IDL specification.
47 *
48 * @author      Bryan Atsatt
49 */
50public class IDLNames implements sun.rmi.rmic.iiop.Constants {
51
52    /**
53     * Used to convert ascii to hex.
54     */
55    public static final byte ASCII_HEX[] =      {
56        (byte)'0',
57        (byte)'1',
58        (byte)'2',
59        (byte)'3',
60        (byte)'4',
61        (byte)'5',
62        (byte)'6',
63        (byte)'7',
64        (byte)'8',
65        (byte)'9',
66        (byte)'A',
67        (byte)'B',
68        (byte)'C',
69        (byte)'D',
70        (byte)'E',
71        (byte)'F',
72    };
73
74    // Legal IDL Identifier characters (1 = legal). Note
75    // that '.' (2E) is marked as legal even though it is
76    // not legal in IDL. This allows us to treat a fully
77    // qualified Java name with '.' package separators
78    // uniformly, and is safe because that is the only
79    // legal use of '.' in a Java name.
80
81    private static final byte[] IDL_IDENTIFIER_CHARS = {
82
83        // 0 1 2 3  4 5 6 7  8 9 a b  c d e f
84        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 00-0f
85        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 10-1f
86        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,1,0, // 20-2f
87        1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0, // 30-3f
88        0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 40-4f
89        1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,1, // 50-5f
90        0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // 60-6f
91        1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0, // 70-7f
92        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 80-8f
93        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 90-9f
94        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // a0-af
95        0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // b0-bf
96        1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // c0-cf
97        0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // d0-df
98        1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1, // e0-ef
99        0,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,0,1, // f0-ff
100    };
101
102    //_____________________________________________________________________
103    // Public Interfaces
104    //_____________________________________________________________________
105
106    /**
107     * Convert a name. The nameContext argument MUST be pre-filled with
108     * all names from the appropriate context (e.g. all the method names
109     * in a given class). The names must not have had any IDL conversions
110     * applied.
111     * <p>
112     * Section 28.3.2.2
113     * Section 28.3.2.3
114     * Section 28.3.2.4
115     * Section 28.3.2.7 (member and method names only)
116     */
117    public static String getMemberOrMethodName (NameContext nameContext,
118                                                String name,
119                                                BatchEnvironment env) {
120
121        // Check namesCache...
122
123        String result = (String) env.namesCache.get(name);
124
125        if (result == null) {
126
127            // 28.3.2.7 Case sensitive member names.
128
129            // Note:    This must be done before any of
130            //          the other conversions!
131
132            result = nameContext.get(name);
133
134            // 28.3.2.3 Leading underscores...
135
136            result = convertLeadingUnderscores(result);
137
138            // 28.3.2.2 IDL keywords (NOTE: must be done
139            // after leading underscore conversion because
140            // the mangling for IDL keywords creates a
141            // leading underscore!)...
142
143            result = convertIDLKeywords(result);
144
145            // 28.3.2.4 Illegal IDL identifier characters...
146
147            result = convertToISOLatin1(result);
148
149            // Add to namesCache...
150
151            env.namesCache.put(name,result);
152        }
153
154        return result;
155    }
156
157    /**
158     * Convert names with illegal IDL identifier characters.
159     * <p>
160     * Section 28.3.2.4
161     */
162    public static String convertToISOLatin1 (String name) {
163
164        // First, replace any escape sequences...
165
166        String result = replace(name,"x\\u","U");
167        result = replace(result,"x\\U","U");
168
169        // Now see if we have any remaining illegal characters (see
170        // IDL_IDENTIFIER_CHARS array)...
171
172        int length = result.length();
173        StringBuffer buffer = null;
174
175        for (int i = 0; i < length; i++) {
176
177            char c = result.charAt(i);
178
179            if (c > 255 || IDL_IDENTIFIER_CHARS[c] == 0) {
180
181                // We gotta convert. Have we already started?
182
183                if (buffer == null) {
184
185                    // No, so get set up...
186
187                    buffer = new StringBuffer(result.substring(0,i));
188                }
189
190                // Convert the character into the IDL escape syntax...
191
192                buffer.append("U");
193                buffer.append((char)ASCII_HEX[(c & 0xF000) >>> 12]);
194                buffer.append((char)ASCII_HEX[(c & 0x0F00) >>> 8]);
195                buffer.append((char)ASCII_HEX[(c & 0x00F0) >>> 4]);
196                buffer.append((char)ASCII_HEX[(c & 0x000F)]);
197
198            } else {
199                if (buffer != null) {
200                    buffer.append(c);
201                }
202            }
203        }
204
205        if (buffer != null) {
206            result = buffer.toString();
207        }
208
209        return result;
210    }
211
212    /**
213     * Convert names which collide with IDL keywords.
214     * <p>
215     * Section 28.3.2.5
216     */
217    public static String convertIDLKeywords (String name) {
218
219        for (int i = 0; i < IDL_KEYWORDS.length; i++) {
220            if (name.equalsIgnoreCase(IDL_KEYWORDS[i])) {
221                return "_" + name;
222            }
223        }
224
225        return name;
226    }
227
228    /**
229     * Convert names which have leading underscores
230     * <p>
231     * Section 28.3.2.3
232     */
233    public static String convertLeadingUnderscores (String name) {
234
235        if (name.startsWith("_")) {
236            return "J" + name;
237        }
238
239        return name;
240    }
241
242    /**
243     * Convert a type name.
244     * <p>
245     * Section 28.3.2.5
246     * Section 28.3.2.7 (class or interface names only)
247     * Throws exception if fails 28.3.2.7.
248     */
249    public static String getClassOrInterfaceName (Identifier id,
250                                                  BatchEnvironment env) throws Exception {
251
252        // Get the type and package name...
253
254        String typeName = id.getName().toString();
255        String packageName = null;
256
257        if (id.isQualified()) {
258            packageName = id.getQualifier().toString();
259        }
260
261        // Check namesCache...
262
263        String result = (String) env.namesCache.get(typeName);
264
265        if (result == null) {
266
267            // 28.3.2.5 Inner classes...
268
269            result = replace(typeName,". ","__");
270
271            // 28.3.2.4 Illegal identifier characters...
272
273            result = convertToISOLatin1(result);
274
275            // 28.3.2.7 Case sensitive class or interface names...
276
277            NameContext context = NameContext.forName(packageName,false,env);
278            context.assertPut(result);
279
280            // Run it through the name checks...
281
282            result = getTypeOrModuleName(result);
283
284            // Add it to the namesCache...
285
286            env.namesCache.put(typeName,result);
287        }
288
289        return result;
290    }
291
292    /**
293     * Convert an Exception name.
294     * <p>
295     * Section 28.3.7.2    (see ValueType)
296     */
297    public static String getExceptionName (String idlName) {
298
299        String result = idlName;
300// d.11315 Incorrectly mangled exception names
301        if (idlName.endsWith(EXCEPTION_SUFFIX)) {
302
303            // Remove "Exception" and append "Ex". Strip leading underscore
304            // in case the idlName is exactly "_Exception"...
305
306            result = stripLeadingUnderscore(idlName.substring(0,idlName.lastIndexOf(EXCEPTION_SUFFIX)) + EX_SUFFIX);
307        } else {
308            result = idlName + EX_SUFFIX;
309        }
310
311        return result;
312    }
313
314    /**
315     * Convert a qualified Identifier into an array of IDL names.
316     * <p>
317     * Section 28.3.2.1    (see CompoundType)
318     * Throws exception if fails 28.3.2.7.
319     */
320    public static String[] getModuleNames (Identifier theID,
321                                           boolean boxIt,
322                                           BatchEnvironment env) throws Exception {
323
324        String[] result = null;
325
326        if (theID.isQualified()) {
327
328            // Extract the qualifier...
329
330            Identifier id = theID.getQualifier();
331
332            // 28.3.2.7 Case sensitive module names.
333
334            env.modulesContext.assertPut(id.toString());
335
336            // Count them...
337
338            int count = 1;
339            Identifier current = id;
340            while (current.isQualified()) {
341                current = current.getQualifier();
342                count++;
343            }
344
345            result = new String[count];
346            int index = count-1;
347            current = id;
348
349            // Now walk them and fill our array (backwards)...
350
351            for (int i = 0; i < count; i++) {
352
353                String item = current.getName().toString();
354
355                // Check namesCache...
356
357                String cachedItem = (String) env.namesCache.get(item);
358
359                if (cachedItem == null) {
360
361                    // 28.3.2.4 Illegal identifier characters...
362
363                    cachedItem = convertToISOLatin1(item);
364
365                    // Run it through the name checks...
366
367                    cachedItem = getTypeOrModuleName(cachedItem);
368
369                    // Add it to the namesCache...
370
371                    env.namesCache.put(item,cachedItem);
372                }
373
374                result[index--] = cachedItem;
375                current = current.getQualifier();
376            }
377        }
378
379
380        // If it is supposed to be "boxed", prepend
381        // IDL_BOXEDIDL_MODULE...
382
383        if (boxIt) {
384            if (result == null) {
385                result = IDL_BOXEDIDL_MODULE;
386            } else {
387            String[] boxed = new String[result.length+IDL_BOXEDIDL_MODULE.length];
388            System.arraycopy(IDL_BOXEDIDL_MODULE,0,boxed,0,IDL_BOXEDIDL_MODULE.length);
389            System.arraycopy(result,0,boxed,IDL_BOXEDIDL_MODULE.length,result.length);
390            result = boxed;
391        }
392        }
393
394        return result;
395    }
396
397    /**
398     * Get an array name with the specified dimensions.
399     * <p>
400     * Section 28.3.6  (see ArrayType)
401     */
402    public static String getArrayName (Type theType, int arrayDimension) {
403
404        StringBuffer idlName = new StringBuffer(64);
405
406        // Prefix with seq<n>_...
407
408        idlName.append(IDL_SEQUENCE);
409        idlName.append(Integer.toString(arrayDimension));
410        idlName.append("_");
411
412        // Add the type name. We need to map any spaces in the
413        // name to "_"...
414
415        idlName.append(replace(stripLeadingUnderscore(theType.getIDLName())," ","_"));
416
417        // And we're done...
418
419        return idlName.toString();
420    }
421
422    /**
423     * Get an array module names.
424     */
425    public static String[] getArrayModuleNames (Type theType) {
426
427        String[] moduleName;
428        String[] typeModule = theType.getIDLModuleNames();
429        int typeModuleLength = typeModule.length;
430
431        // Does the type have a module?
432
433        if (typeModuleLength == 0) {
434
435            // Nope, so just use the sequence module...
436
437            moduleName = IDL_SEQUENCE_MODULE;
438        } else {
439
440            // Yes, so gotta concatenate...
441
442            moduleName = new String[typeModuleLength + IDL_SEQUENCE_MODULE.length];
443            System.arraycopy(IDL_SEQUENCE_MODULE,0,moduleName,0,IDL_SEQUENCE_MODULE.length);
444            System.arraycopy(typeModule,0,moduleName,IDL_SEQUENCE_MODULE.length,typeModuleLength);
445        }
446
447        return moduleName;
448    }
449
450    private static int getInitialAttributeKind (CompoundType.Method method,
451                                                BatchEnvironment env) throws ClassNotFound {
452
453        int result = ATTRIBUTE_NONE;
454
455        // First make sure it is not a constructor...
456
457        if (!method.isConstructor()) {
458
459            // Now check exceptions. It may not throw any checked
460            // exception other than RemoteException or one of its
461            // subclasses...
462
463            boolean validExceptions = true;
464            ClassType[] exceptions = method.getExceptions();
465
466            if (exceptions.length > 0) {
467                for (int i = 0; i < exceptions.length; i++) {
468                    if (exceptions[i].isCheckedException() &&
469                        !exceptions[i].isRemoteExceptionOrSubclass()) {
470                        validExceptions = false;
471                        break;
472                    }
473                }
474            } else {
475
476                // If this is a ValueType, it is ok to not have any exceptions,
477                // otherwise this method does not qualify...
478
479                validExceptions = method.getEnclosing().isType(TYPE_VALUE);
480            }
481
482            if (validExceptions) {
483                String name = method.getName();
484                int nameLength = name.length();
485                int argCount = method.getArguments().length;
486                Type returnType = method.getReturnType();
487                boolean voidReturn = returnType.isType(TYPE_VOID);
488                boolean booleanReturn = returnType.isType(TYPE_BOOLEAN);
489
490                // It's a getter if name starts with "get" and it has no arguments
491                // and a return type that is not void...
492
493                if (name.startsWith("get") && nameLength > 3 && argCount == 0 && !voidReturn) {
494                    result = ATTRIBUTE_GET;
495                } else {
496
497                    // It's a getter if name starts with "is" and it has no arguments
498                    // and a boolean return type...
499
500                    if (name.startsWith("is") && nameLength > 2 && argCount == 0 && booleanReturn) {
501                        result = ATTRIBUTE_IS;
502                    } else {
503
504                        // It's a setter if name starts with "set" and it has 1 argument
505                        // and a void return type...
506
507                        if (name.startsWith("set") && nameLength > 3 && argCount == 1 && voidReturn) {
508                            result = ATTRIBUTE_SET;
509                        }
510                    }
511                }
512            }
513        }
514
515        return result;
516    }
517
518    private static void setAttributeKinds (CompoundType.Method[] methods,
519                                           int[] kinds,
520                                           String[] names) {
521
522        int count = methods.length;
523
524        // Strip the prefixes off of the attribute names...
525
526        for (int i = 0; i < count; i++) {
527            switch (kinds[i]) {
528                case ATTRIBUTE_GET: names[i] = names[i].substring(3); break;
529                case ATTRIBUTE_IS: names[i] = names[i].substring(2); break;
530                case ATTRIBUTE_SET: names[i] = names[i].substring(3); break;
531            }
532        }
533
534        // Now, we need to look at all the IS attributes to see
535        // if there is a corresponding getter or setter which has
536        // a different return type. If so, mark it as not an
537        // attribute. Do this before checking for invalid setters...
538
539        for (int i = 0; i < count; i++) {
540            if (kinds[i] == ATTRIBUTE_IS) {
541                for (int j = 0; j < count; j++) {
542                    if (j != i &&
543                        (kinds[j] == ATTRIBUTE_GET || kinds[j] == ATTRIBUTE_SET) &&
544                        names[i].equals(names[j])) {
545
546                        // We have matching getter or setter. Do the types match?
547
548                        Type isType = methods[i].getReturnType();
549                        Type targetType;
550
551                        if (kinds[j] == ATTRIBUTE_GET) {
552                            targetType = methods[j].getReturnType();
553                        } else {
554                            targetType = methods[j].getArguments()[0];
555                        }
556
557                        if (!isType.equals(targetType)) {
558
559                            // No, so forget this guy as an attribute...
560
561                            kinds[i] = ATTRIBUTE_NONE;
562                            names[i] = methods[i].getName();
563                            break;
564                        }
565                    }
566                }
567            }
568        }
569
570        // Now, we need to look at all the setters to see if there
571        // is a corresponding getter. If not, it is not a setter.
572        // If there is, change the getter type to _RW and set the
573        // pair index...
574
575        for (int i = 0; i < count; i++) {
576            if (kinds[i] == ATTRIBUTE_SET) {
577                int getterIndex = -1;
578                int isGetterIndex = -1;
579                // First look for is-getters, then for getters.
580                // This is preferred for boolean attributes.
581                for (int j = 0; j < count; j++) {
582                    if (j != i && names[i].equals(names[j])) {
583                        // Yep, is the return type of the getter the same
584                        // as the argument type of the setter?
585
586                        Type getterReturn = methods[j].getReturnType();
587                        Type setterArg = methods[i].getArguments()[0];
588
589                        if (getterReturn.equals(setterArg)) {
590                            if (kinds[j] == ATTRIBUTE_IS) {
591                                isGetterIndex = j;
592                                // continue looking for another getter
593                            } else if (kinds[j] == ATTRIBUTE_GET) {
594                                getterIndex = j;
595                                // continue looking for an is-getter
596                            }
597                        }
598                    }
599                }
600
601                if (getterIndex > -1) {
602                    if (isGetterIndex > -1) {
603                        // We have both, a boolean is-getter and a boolean getter.
604                        // Use the is-getter and drop the getter.
605
606                        // We have a matching getter. Change it to a read-write type...
607                        kinds[isGetterIndex] = ATTRIBUTE_IS_RW;
608
609                        // Now set the pair index for both the getter and the setter...
610                        methods[isGetterIndex].setAttributePairIndex(i);
611                        methods[i].setAttributePairIndex(isGetterIndex);
612
613                        // We found a better matching is-getter.
614                        // Forget this other getter as an attribute.
615                        kinds[getterIndex] = ATTRIBUTE_NONE;
616                        names[getterIndex] = methods[getterIndex].getName();
617                    } else {
618                        // We only have one getter.
619
620                        // We have a matching getter. Change it to a read-write type...
621                        kinds[getterIndex] = ATTRIBUTE_GET_RW;
622
623                        // Now set the pair index for both the getter and the setter...
624                        methods[getterIndex].setAttributePairIndex(i);
625                        methods[i].setAttributePairIndex(getterIndex);
626                    }
627                } else {
628                    if (isGetterIndex > -1) {
629                        // We only have one is-getter.
630
631                        // We have a matching getter. Change it to a read-write type...
632                        kinds[isGetterIndex] = ATTRIBUTE_IS_RW;
633
634                        // Now set the pair index for both the getter and the setter...
635                        methods[isGetterIndex].setAttributePairIndex(i);
636                        methods[i].setAttributePairIndex(isGetterIndex);
637                    } else {
638                        // We did not find a matching getter.
639                        // Forget this setter as an attribute.
640                        kinds[i] = ATTRIBUTE_NONE;
641                        names[i] = methods[i].getName();
642                    }
643                }
644            }
645        }
646
647        // Finally, do the case conversion and set the
648        // attribute kinds for each method...
649
650        for (int i = 0; i < count; i++) {
651
652            if (kinds[i] != ATTRIBUTE_NONE) {
653
654                String name = names[i];
655
656                // Is the first character upper case?
657
658                if (Character.isUpperCase(name.charAt(0))) {
659
660                    // Yes, is the second?
661
662                    if (name.length() == 1 || Character.isLowerCase(name.charAt(1))) {
663
664                        // No, so convert the first character to lower case...
665
666                        StringBuffer buffer = new StringBuffer(name);
667                        buffer.setCharAt(0,Character.toLowerCase(name.charAt(0)));
668                        names[i] = buffer.toString();
669                    }
670                }
671            }
672
673            methods[i].setAttributeKind(kinds[i]);
674        }
675    }
676
677    /**
678     * Set all the method names in a given class.
679     * <p>
680     * Section 28.3.2.7    (see CompoundType)
681     * Section 28.3.2.7
682     * Section 28.3.4.3 (RemoteType/AbstractType only).
683     */
684    public static void setMethodNames (CompoundType container,
685                                       CompoundType.Method[] allMethods,
686                                       BatchEnvironment env)
687        throws Exception {
688
689        // This method implements the following name mangling sequence:
690        //
691        //   1. If methods belong to a Remote interface, identify
692        //      those which qualify as an attribute under 28.3.4.3.
693        //      Those that do are referred to as 'attributes' below;
694        //      those that do not are referred to as 'methods'.
695        //
696        //   2. Apply the 28.3.4.3 manglings, except "__", to all
697        //      attribute names.
698        //
699        //   3. Apply all 28.3 manglings, except 28.3.2.7, to all names.
700        //
701        //   4. Apply 28.3.2.7 manglings to all method names.
702        //
703        //   5. Compare each attribute name to each method name. For
704        //      any which compare equal, append "__" to the attribute
705        //      name.
706        //
707        //   6. Compare each name (attribute and method) to all others.
708        //      If any compare equal, throw an Exception with the
709        //      conflicting name as the message.
710
711        int count = allMethods.length;
712
713        if (count == 0) return;
714
715        // Make an array of all the method names...
716
717        String[] names = new String[count];
718        for (int i = 0; i < count; i++) {
719            names[i] = allMethods[i].getName();
720        }
721
722        // Are we dealing with a RemoteType, AbstractType, or ValueType?
723
724        CompoundType enclosing = allMethods[0].getEnclosing();
725        if (enclosing.isType(TYPE_REMOTE) ||
726            enclosing.isType(TYPE_ABSTRACT) ||
727            enclosing.isType(TYPE_VALUE)) {
728
729            // Yes, so we must do the 28.3.4.3 attribute mapping. First, get
730            // the initial attribute kind of each method...
731
732            int[] kinds = new int[count];
733
734            for (int i = 0; i < count; i++) {
735                kinds[i] = getInitialAttributeKind(allMethods[i],env);
736            }
737
738            // Now set the attribute kind for each method and do the
739            // 28.3.4.3 name mangling...
740
741            setAttributeKinds(allMethods,kinds,names);
742        }
743
744        // Make and populate a new context from our names array...
745
746        NameContext context = new NameContext(true);
747
748        for (int i = 0; i < count; i++) {
749            context.put(names[i]);
750        }
751
752        // Apply the appropriate 28.3 manglings to all the names...
753
754        boolean haveConstructor = false;
755        for (int i = 0; i < count; i++) {
756            if (!allMethods[i].isConstructor()) {
757                names[i] = getMemberOrMethodName(context,names[i],env);
758            } else {
759                names[i] = IDL_CONSTRUCTOR;
760                haveConstructor = true;
761            }
762        }
763
764        // Now do the 28.3.2.7 mangling for method name collisions...
765        // Do this in two passes so that we don't change one during
766        // the detection of collisions and then miss a real one...
767
768        boolean overloaded[] = new boolean[count];
769        for (int i = 0; i < count; i++) {
770            overloaded[i] = (!allMethods[i].isAttribute() &&
771                             !allMethods[i].isConstructor() &&
772                         doesMethodCollide(names[i],allMethods[i],allMethods,names,true));
773        }
774        convertOverloadedMethods(allMethods,names,overloaded);
775
776        // Now do the same mangling for constructor name collisions...
777
778        for (int i = 0; i < count; i++) {
779            overloaded[i] = (!allMethods[i].isAttribute() &&
780                             allMethods[i].isConstructor() &&
781                             doesConstructorCollide(names[i],allMethods[i],allMethods,names,true));
782        }
783        convertOverloadedMethods(allMethods,names,overloaded);
784
785        // Now do the 28.3.4.3 mangling for attribute name collisions...
786
787        for (int i = 0; i < count; i++) {
788
789                CompoundType.Method method = allMethods[i];
790
791            // If this is an attribute name, does it collide with a method?
792
793            if (method.isAttribute() &&
794                doesMethodCollide(names[i],method,allMethods,names,true)) {
795
796                // Yes, so add double underscore...
797
798                    names[i] += "__";
799                }
800            }
801
802        // Do the same mangling for any constructors which collide with
803        // methods...
804
805        if (haveConstructor) {
806        for (int i = 0; i < count; i++) {
807            CompoundType.Method method = allMethods[i];
808
809                // Is this a constructor which collides with a method?
810
811                if (method.isConstructor() &&
812                    doesConstructorCollide(names[i],method,allMethods,names,false)) {
813
814                // Yes, so add double underscore...
815
816                names[i] += "__";
817            }
818        }
819        }
820
821        // Now see if we have a collision with the container name (28.3.2.9).
822
823        String containerName = container.getIDLName();
824        for (int i = 0; i < count; i++) {
825            if (names[i].equalsIgnoreCase(containerName)) {
826                // Do not add underscore to attributes.
827                // Otherwise getFoo will turn into _get_foo_.
828                if (! allMethods[i].isAttribute()) {
829                    names[i] += "_";
830                }
831            }
832        }
833
834        // Now see if we have any collisions (28.3.2.9). If we do,
835        // it's an error.  Note: a get/set pair does not collide.
836
837        for (int i = 0; i < count; i++) {
838
839            // Does it collide with any other name?
840
841            if (doesMethodCollide(names[i],allMethods[i],allMethods,names,false)) {
842
843                // Yes, so bail...
844
845                throw new Exception(allMethods[i].toString());
846            }
847        }
848
849        // Ok. We have unique names. Create the appropriate 'wire' name
850        // for each and set as the 'idl' name. If it is an attribute, also
851        // set the attribute name...
852
853        for (int i = 0; i < count; i++) {
854
855            CompoundType.Method method = allMethods[i];
856            String wireName = names[i];
857
858            if (method.isAttribute()) {
859                wireName = ATTRIBUTE_WIRE_PREFIX[method.getAttributeKind()] +
860                    stripLeadingUnderscore(wireName);
861                String attributeName = names[i];
862                method.setAttributeName(attributeName);
863            }
864            method.setIDLName(wireName);
865        }
866    }
867
868    private static String stripLeadingUnderscore (String name) {
869        if (name != null && name.length() > 1
870            && name.charAt(0) == '_')
871        {
872            return name.substring(1);
873        }
874        return name;
875    }
876
877
878    private static String stripTrailingUnderscore (String name) {
879        if (name != null && name.length() > 1 &&
880            name.charAt(name.length() - 1) == '_')
881        {
882            return name.substring(0, name.length() - 1);
883        }
884        return name;
885    }
886
887
888    private static void convertOverloadedMethods(CompoundType.Method[] allMethods,
889                                                 String[] names,
890                                                 boolean[] overloaded) {
891
892        for (int i = 0; i < names.length; i++) {
893
894            // Do we need to mangle it?
895
896            if (overloaded[i]) {
897
898                // Yes, so add arguments...
899
900                CompoundType.Method method = allMethods[i];
901                Type[] args = method.getArguments();
902
903                for (int k = 0; k < args.length; k++) {
904
905                                // Add the separator...
906
907                    names[i] += "__";
908
909                                // Get the fully qualified IDL name, without the "::"
910                                // prefix...
911
912                    String argIDLName = args[k].getQualifiedIDLName(false);
913
914                                // Replace any occurances of "::_" with "_" to
915                                // undo any IDL keyword mangling and do next step
916                                // at the same time...
917
918                    argIDLName = replace(argIDLName,"::_","_");
919
920                                // Replace any occurances of "::" with "_"...
921
922                    argIDLName = replace(argIDLName,"::","_");
923
924                                // Replace any occurances of " " with "_"...
925
926                    argIDLName = replace(argIDLName," ","_");
927
928                                // Add the argument type name...
929
930                    names[i] += argIDLName;
931                }
932
933                if (args.length == 0) {
934                    names[i] += "__";
935                }
936
937                // Remove any IDL keyword mangling...
938
939                names[i] = stripLeadingUnderscore(names[i]);
940            }
941        }
942    }
943
944    private static boolean doesMethodCollide (String name,
945                                              CompoundType.Method method,
946                                              CompoundType.Method[] allMethods,
947                                              String[] allNames,
948                                              boolean ignoreAttributes) {
949
950        // Scan all methods looking for a match...
951
952        for (int i = 0; i < allMethods.length; i++) {
953
954            CompoundType.Method target = allMethods[i];
955
956            if (method != target &&                                 // Not same instance
957                !target.isConstructor() &&                      // Not a constructor
958                (!ignoreAttributes || !target.isAttribute()) && // Correct kind
959                name.equals(allNames[i])) {                         // Same names
960
961                // Are we looking at a get/set pair?
962
963                int kind1 = method.getAttributeKind();
964                int kind2 = target.getAttributeKind();
965
966                if ((kind1 != ATTRIBUTE_NONE && kind2 != ATTRIBUTE_NONE) &&
967                    ((kind1 == ATTRIBUTE_SET && kind2 != ATTRIBUTE_SET) ||
968                     (kind1 != ATTRIBUTE_SET && kind2 == ATTRIBUTE_SET) ||
969                     // one is a is-getter/setter pair and the other is just a getter
970                     (kind1 == ATTRIBUTE_IS_RW && kind2 == ATTRIBUTE_GET) ||
971                     (kind1 == ATTRIBUTE_GET && kind2 == ATTRIBUTE_IS_RW))) {
972
973                    // Yes, so ignore it...
974
975                } else {
976
977                    // No, so we have a collision...
978
979                    return true;
980                }
981            }
982        }
983
984        return false;
985    }
986
987    private static boolean doesConstructorCollide (String name,
988                                                   CompoundType.Method method,
989                                                   CompoundType.Method[] allMethods,
990                                                   String[] allNames,
991                                                   boolean compareConstructors) {
992
993        // Scan all methods looking for a match...
994
995        for (int i = 0; i < allMethods.length; i++) {
996
997            CompoundType.Method target = allMethods[i];
998
999            if (method != target &&                                     // Not same instance
1000                (target.isConstructor() == compareConstructors) &&  // Correct kind
1001                name.equals(allNames[i])) {                             // Same names
1002
1003                // We have a collision...
1004
1005                return true;
1006            }
1007        }
1008
1009        return false;
1010    }
1011
1012
1013    /**
1014     * Set all the member names in a given class.
1015     * <p>
1016     * Section 28.3.2.7    (see CompoundType)
1017     * Section 28.3.2.7
1018     */
1019    public static void setMemberNames (CompoundType container,
1020                                       CompoundType.Member[] allMembers,
1021                                       CompoundType.Method[] allMethods,
1022                                       BatchEnvironment env)
1023        throws Exception {
1024
1025        // Make and populate a new context...
1026
1027        NameContext context = new NameContext(true);
1028
1029        for (int i = 0; i < allMembers.length; i++) {
1030            context.put(allMembers[i].getName());
1031        }
1032
1033        // Now set all the idl names...
1034
1035        for (int i = 0; i < allMembers.length; i++) {
1036
1037            CompoundType.Member member = allMembers[i];
1038            String idlName = getMemberOrMethodName(context,member.getName(),env);
1039            member.setIDLName(idlName);
1040        }
1041
1042        // First see if we have a collision with the container name (28.3.2.9).
1043
1044        String containerName = container.getIDLName();
1045        for (int i = 0; i < allMembers.length; i++) {
1046            String name = allMembers[i].getIDLName();
1047            if (name.equalsIgnoreCase(containerName)) {
1048                // REVISIT - How is this different than line 788
1049                allMembers[i].setIDLName(name+"_");
1050            }
1051        }
1052
1053        // Check for collisions between member names...
1054
1055        for (int i = 0; i < allMembers.length; i++) {
1056            String name = allMembers[i].getIDLName();
1057            for (int j = 0; j < allMembers.length; j++) {
1058                if (i != j && allMembers[j].getIDLName().equals(name)) {
1059
1060                    // Collision...
1061
1062                    throw new Exception(name);
1063                }
1064            }
1065        }
1066
1067        // Now check for collisions between member names and
1068        // method names...
1069
1070        boolean changed;
1071        do {
1072            changed = false;
1073            for (int i = 0; i < allMembers.length; i++) {
1074                String name = allMembers[i].getIDLName();
1075                for (int j = 0; j < allMethods.length; j++) {
1076                    if (allMethods[j].getIDLName().equals(name)) {
1077
1078                        // Collision, so append "_" to member name...
1079
1080                        allMembers[i].setIDLName(name+"_");
1081                        changed = true;
1082                        break;
1083                    }
1084                }
1085            }
1086        } while (changed);
1087    }
1088
1089    /**
1090     * Get the name for the specified type code.
1091     * <p>
1092     * Section 28.3..3     (see PrimitiveType)
1093     * Section 28.3.5.10   (see SpecialClassType)
1094     * Section 28.3.4.1    (see SpecialInterfaceType)
1095     * Section 28.3.10.1   (see SpecialInterfaceType)
1096     * Section 28.3.10.2   (see SpecialClassType)
1097     */
1098    public static String getTypeName(int typeCode, boolean isConstant) {
1099
1100        String idlName = null;
1101
1102        switch (typeCode) {
1103        case TYPE_VOID:             idlName = IDL_VOID; break;
1104        case TYPE_BOOLEAN:          idlName = IDL_BOOLEAN; break;
1105        case TYPE_BYTE:             idlName = IDL_BYTE; break;
1106        case TYPE_CHAR:             idlName = IDL_CHAR; break;
1107        case TYPE_SHORT:            idlName = IDL_SHORT; break;
1108        case TYPE_INT:              idlName = IDL_INT; break;
1109        case TYPE_LONG:             idlName = IDL_LONG; break;
1110        case TYPE_FLOAT:            idlName = IDL_FLOAT; break;
1111        case TYPE_DOUBLE:           idlName = IDL_DOUBLE; break;
1112        case TYPE_ANY:                  idlName = IDL_ANY; break;
1113        case TYPE_CORBA_OBJECT: idlName = IDL_CORBA_OBJECT; break;
1114        case TYPE_STRING:
1115            {
1116                if (isConstant) {
1117                    idlName = IDL_CONSTANT_STRING;
1118                } else {
1119                    idlName = IDL_STRING;
1120                }
1121
1122                break;
1123            }
1124        }
1125
1126        return idlName;
1127    }
1128
1129    /**
1130     * Create a qualified name.
1131     */
1132    public static String getQualifiedName (String[] idlModuleNames, String idlName) {
1133        String result = null;
1134        if (idlModuleNames != null && idlModuleNames.length > 0) {
1135            for (int i = 0; i < idlModuleNames.length;i++) {
1136                if (i == 0) {
1137                    result = idlModuleNames[0];
1138                } else {
1139                    result += IDL_NAME_SEPARATOR;
1140                    result += idlModuleNames[i];
1141                }
1142            }
1143            result += IDL_NAME_SEPARATOR;
1144            result += idlName;
1145        } else {
1146            result = idlName;
1147        }
1148        return result;
1149    }
1150
1151    /**
1152     * Replace substrings
1153     * @param source The source string.
1154     * @param match The string to search for within the source string.
1155     * @param replace The replacement for any matching components.
1156     * @return
1157     */
1158    public static String replace (String source, String match, String replace) {
1159
1160        int index = source.indexOf(match,0);
1161
1162        if (index >=0) {
1163
1164            // We have at least one match, so gotta do the
1165            // work...
1166
1167            StringBuffer result = new StringBuffer(source.length() + 16);
1168            int matchLength = match.length();
1169            int startIndex = 0;
1170
1171            while (index >= 0) {
1172                result.append(source.substring(startIndex,index));
1173                result.append(replace);
1174                startIndex = index + matchLength;
1175                index = source.indexOf(match,startIndex);
1176            }
1177
1178            // Grab the last piece, if any...
1179
1180            if (startIndex < source.length()) {
1181                result.append(source.substring(startIndex));
1182            }
1183
1184            return result.toString();
1185
1186        } else {
1187
1188            // No matches, just return the source...
1189
1190            return source;
1191        }
1192    }
1193
1194    /**
1195     * Get an IDL style repository id for
1196     */
1197    public static String getIDLRepositoryID (String idlName) {
1198        return  IDL_REPOSITORY_ID_PREFIX +
1199            replace(idlName,"::", "/") +
1200            IDL_REPOSITORY_ID_VERSION;
1201    }
1202
1203    //_____________________________________________________________________
1204    // Internal Interfaces
1205    //_____________________________________________________________________
1206
1207
1208    /**
1209     * Convert a type or module name.
1210     * <p>
1211     * Section 28.3.2.2
1212     * Section 28.3.2.3
1213     */
1214    private static String getTypeOrModuleName (String name) {
1215
1216        // 28.3.2.3 Leading underscores...
1217
1218        String result = convertLeadingUnderscores(name);
1219
1220        // 28.3.2.2 IDL keywords (NOTE: must be done
1221        // after leading underscore conversion because
1222        // the mangling for IDL keywords creates a
1223        // leading underscore!)...
1224
1225        return convertIDLKeywords(result);
1226    }
1227}
1228