org.eclipse.jdt.internal.core.builder.ReferenceCollection.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.jdt.internal.core.builder.ReferenceCollection.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2010 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Tim Hanson <thanson@bea.com> - fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=137634
 *     Sebastian Zarnekow - Contribution for
 *                        Bug 545491 - Poor performance of ReferenceCollection with many source files
 *******************************************************************************/
package org.eclipse.jdt.internal.core.builder;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Set;
import java.util.stream.Collectors;

import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.util.SortedCharArrays;

public class ReferenceCollection {

    // contains no simple names as in just 'a' which is kept in simpleNameReferences instead
    // TODO after #addDependencies, it will contain simple names, though. See ReferenceCollectionTest
    char[][][] qualifiedNameReferences;
    char[][] simpleNameReferences;
    char[][] rootReferences;

    protected ReferenceCollection(char[][][] qualifiedNameReferences, char[][] simpleNameReferences,
            char[][] rootReferences) {
        this.qualifiedNameReferences = internQualifiedNames(qualifiedNameReferences, false);
        this.simpleNameReferences = internSimpleNames(simpleNameReferences, true);
        this.rootReferences = internSimpleNames(rootReferences, false);
    }

    /**
     * Add the given fully qualified names to this reference collection.
     * Subsequent queries of {@link #includes(char[][][], char[][], char[][])} will report true
     * if the given names intersect with one of the added type name dependencies.
     *
     * @see CompilationUnitScope#recordQualifiedReference
     */
    public void addDependencies(String[] typeNameDependencies) {
        // if each qualified type name is already known then all of its subNames can be skipped
        // and its expected that very few qualified names in typeNameDependencies need to be added
        // but could always take 'p1.p2.p3.X' and make all qualified names 'p1' 'p1.p2' 'p1.p2.p3' 'p1.p2.p3.X', then intern
        next: for (String typeNameDependency : typeNameDependencies) {
            char[][] qualifiedTypeName = CharOperation.splitOn('.', typeNameDependency.toCharArray());
            if (!isWellKnownQualifiedName(qualifiedTypeName)) {
                int qLength = qualifiedTypeName.length;
                QualifiedNameSet internedNames = InternedQualifiedNames[qLength <= MaxQualifiedNames ? qLength - 1
                        : 0];
                qualifiedTypeName = internSimpleNames(qualifiedTypeName, false, false);
                qualifiedTypeName = internedNames.add(qualifiedTypeName);
                int idx;
                while ((idx = Arrays.binarySearch(this.qualifiedNameReferences, qualifiedTypeName,
                        SortedCharArrays.CHAR_CHAR_ARR_COMPARATOR)) < 0) {
                    this.simpleNameReferences = ensureContainedInSortedOrder(this.simpleNameReferences,
                            qualifiedTypeName[qualifiedTypeName.length - 1]);
                    this.rootReferences = ensureContainedInSortedOrder(this.rootReferences, qualifiedTypeName[0]);

                    int length = this.qualifiedNameReferences.length;
                    idx = -(idx + 1);
                    this.qualifiedNameReferences = SortedCharArrays.insertIntoArray(this.qualifiedNameReferences,
                            new char[length + 1][][], qualifiedTypeName, idx, this.qualifiedNameReferences.length);

                    qualifiedTypeName = CharOperation.subarray(qualifiedTypeName, 0, qualifiedTypeName.length - 1);
                    char[][][] temp = internQualifiedNames(new char[][][] { qualifiedTypeName }, false);
                    if (temp == EmptyQualifiedNames)
                        continue next; // qualifiedTypeName is a well known name
                    qualifiedTypeName = temp[0];
                }
            }
        }
    }

    public boolean includes(char[] simpleName) {
        boolean result = sortedArrayContains(this.simpleNameReferences, simpleName,
                SortedCharArrays.CHAR_ARR_COMPARATOR);
        if (REFERENCE_COLLECTION_DEBUG) {
            assertIncludes(result, simpleName);
        }
        return result;
    }

    public boolean includes(char[][] qualifiedName) {
        boolean result = sortedArrayContains(this.qualifiedNameReferences, qualifiedName,
                SortedCharArrays.CHAR_CHAR_ARR_COMPARATOR);
        if (REFERENCE_COLLECTION_DEBUG) {
            assertIncludes(result, qualifiedName);
        }
        return result;
    }

    private static String qualifiedNamesToString(char[][][] qualifiedNames) {
        if (qualifiedNames == null)
            return "null"; //$NON-NLS-1$
        return Arrays.stream(qualifiedNames).map(CharOperation::toString).collect(Collectors.joining(",")); //$NON-NLS-1$
    }

    /**
     * @deprecated
     */
    public boolean includes(char[][][] qualifiedNames, char[][] simpleNames) {
        return includes(qualifiedNames, simpleNames, null);
    }

    public boolean includes(char[][][] qualifiedNames, char[][] simpleNames, char[][] rootNames) {
        boolean result = doIncludes(qualifiedNames, simpleNames, rootNames);
        if (REFERENCE_COLLECTION_DEBUG) {
            assertIncludes(result, qualifiedNames, simpleNames, rootNames);
        }
        return result;
    }

    private boolean doIncludes(char[][][] qualifiedNames, char[][] simpleNames, char[][] rootNames) {
        if (rootNames != null) {
            if (!includesRootName(rootNames))
                return false;
        }
        // if either collection of names is null, it means it contained a well known name so we know it already has a match
        if (simpleNames == null || qualifiedNames == null) {
            if (simpleNames == null && qualifiedNames == null) {
                if (JavaBuilder.DEBUG)
                    System.out.println("Found well known match"); //$NON-NLS-1$
                return true;
            } else if (qualifiedNames == null) {
                return includesSimpleName(simpleNames);
            }
            return includesQualifiedName(qualifiedNames);
        }

        if (simpleNames.length <= qualifiedNames.length) {
            return includesSimpleName(simpleNames) && includesQualifiedName(qualifiedNames);
        } else {
            return includesQualifiedName(qualifiedNames) && includesSimpleName(simpleNames);
        }
    }

    public boolean insideRoot(char[] rootName) {
        boolean result = sortedArrayContains(this.rootReferences, rootName, SortedCharArrays.CHAR_ARR_COMPARATOR);
        if (REFERENCE_COLLECTION_DEBUG) {
            if (result != debugIncludes(rootName)) {
                String message = "Mismatch: " + String.valueOf(rootName) + (result ? " should not " : " should ") //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                        + " be included in " //$NON-NLS-1$
                        + Arrays.asList(CharOperation.toStrings(this.rootReferences));
                throw new IllegalStateException(message);
            }
        }
        return result;
    }

    private static <T> boolean sortedArrayContains(T[] array, T element, Comparator<? super T> comparator) {
        int l = array.length;
        if (l < SortedCharArrays.BINARY_SEARCH_THRESHOLD) {
            for (int i = 0; i < l; i++)
                if (element == array[i])
                    return true;
            return false;
        }
        return Arrays.binarySearch(array, element, comparator) >= 0;
    }

    private boolean includesSimpleName(char[][] simpleNames) {
        return intersects(simpleNames, this.simpleNameReferences, SortedCharArrays.CHAR_ARR_COMPARATOR);
    }

    private boolean includesQualifiedName(char[][][] qualifiedNames) {
        if (intersects(qualifiedNames, this.qualifiedNameReferences, SortedCharArrays.CHAR_CHAR_ARR_COMPARATOR)) {
            return true;
        }
        char[][] maybeSimpleName;
        for (int i = qualifiedNames.length - 1; i >= 0 && (maybeSimpleName = qualifiedNames[i]).length == 1; i--) {
            if (includes(maybeSimpleName[0])) {
                return true;
            }
        }
        return false;
    }

    private boolean includesRootName(char[][] rootNames) {
        return intersects(rootNames, this.rootReferences, SortedCharArrays.CHAR_ARR_COMPARATOR);
    }

    private static <T> boolean intersects(T[] firstSortedArr, T[] secondSortedArr,
            Comparator<? super T> comparator) {
        /*
         * Both arrays are sorted, so we can walk them in pairs.
         * Using binary search for the remaining array elements to figure the next
         * interesting index can greatly reduce the runtime cost for arrays that do
         * have more than a few elements.
         */
        for (int i = 0, l = firstSortedArr.length, j = 0, k = secondSortedArr.length; i < l && j < k;) {
            T firstElement = firstSortedArr[i];
            T secondElement = secondSortedArr[j];
            int compare = comparator.compare(firstElement, secondElement);
            if (compare == 0) {
                return true;
            } else if (compare < 0) {
                /*
                 * left side is smaller than the right side, but not exactly the right side.
                 * Take the next element from the left and proceed.
                 *
                 * If the number of remaining elements in the first array is sufficiently big,
                 * attempt a binary search for the second element to possibly skip a few elements.
                 */
                i++;
                if (l - i > SortedCharArrays.BINARY_SEARCH_THRESHOLD) {
                    i = Arrays.binarySearch(firstSortedArr, i, l, secondElement, comparator);
                    if (i >= 0) {
                        return true;
                    }
                    i = -(i + 1);
                }
            } else {
                /*
                 * the inverse logic is applied here
                 */
                j++;
                if (k - j > SortedCharArrays.BINARY_SEARCH_THRESHOLD) {
                    j = Arrays.binarySearch(secondSortedArr, j, k, firstElement, comparator);
                    if (j >= 0) {
                        return true;
                    }
                    j = -(j + 1);
                }
            }
        }
        return false;
    }

    private static char[][] ensureContainedInSortedOrder(char[][] sortedArray, char[] entry) {
        int idx = Arrays.binarySearch(sortedArray, entry, SortedCharArrays.CHAR_ARR_COMPARATOR);
        if (idx < 0) {
            idx = -(idx + 1);
            char[][] result = SortedCharArrays.insertIntoArray(sortedArray, new char[sortedArray.length + 1][],
                    entry, idx, sortedArray.length);
            return result;
        }
        return sortedArray;
    }

    private static boolean isWellKnownQualifiedName(char[][] qualifiedName) {
        for (int i = 0, m = WellKnownQualifiedNames.length, qLength = qualifiedName.length; i < m; i++) {
            char[][] wellKnownName = WellKnownQualifiedNames[i];
            if (qLength > wellKnownName.length)
                break; // all remaining well known names are shorter
            if (CharOperation.equals(qualifiedName, wellKnownName)) {
                return true;
            }
        }
        return false;
    }

    // When any type is compiled, its methods are verified for certain problems
    // the MethodVerifier requests 3 well known types which end up in the reference collection
    // having WellKnownQualifiedNames & WellKnownSimpleNames, saves every type 40 bytes
    // NOTE: These collections are sorted by length
    static final char[][][] WellKnownQualifiedNames = new char[][][] { TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION,
            TypeConstants.JAVA_LANG_THROWABLE, TypeConstants.JAVA_LANG_OBJECT, TypeConstants.JAVA_LANG,
            new char[][] { TypeConstants.JAVA }, new char[][] { new char[] { 'o', 'r', 'g' } },
            new char[][] { new char[] { 'c', 'o', 'm' } }, CharOperation.NO_CHAR_CHAR }; // default package
    static final char[][] WellKnownSimpleNames = new char[][] { TypeConstants.JAVA_LANG_RUNTIMEEXCEPTION[2],
            TypeConstants.JAVA_LANG_THROWABLE[2], TypeConstants.JAVA_LANG_OBJECT[2], TypeConstants.JAVA,
            TypeConstants.LANG, new char[] { 'o', 'r', 'g' }, new char[] { 'c', 'o', 'm' } };

    static final char[][][] EmptyQualifiedNames = new char[0][][];
    static final char[][] EmptySimpleNames = CharOperation.NO_CHAR_CHAR;

    // each array contains qualified char[][], one for size 2, 3, 4, 5, 6, 7 & the rest
    static final int MaxQualifiedNames = 7;
    static QualifiedNameSet[] InternedQualifiedNames = new QualifiedNameSet[MaxQualifiedNames];
    // each array contains simple char[], one for size 1 to 29 & the rest
    static final int MaxSimpleNames = 30;
    static NameSet[] InternedSimpleNames = new NameSet[MaxSimpleNames];
    static {
        for (int i = 0; i < MaxQualifiedNames; i++)
            InternedQualifiedNames[i] = new QualifiedNameSet(37);
        for (int i = 0; i < MaxSimpleNames; i++)
            InternedSimpleNames[i] = new NameSet(37);
    }

    //TODO: remove once ReferenceCollection.internQualifiedNames(StringSet) is adapted to use java.util.Set, so that git history is preserved
    public static char[][][] internQualifiedNames(Set<String> qualifiedStrings) {
        if (qualifiedStrings == null)
            return EmptyQualifiedNames;
        int length = qualifiedStrings.size();
        if (length == 0)
            return EmptyQualifiedNames;

        char[][][] result = new char[length][][];
        for (String qualifiedString : qualifiedStrings)
            if (qualifiedString != null)
                result[--length] = CharOperation.splitOn('/', qualifiedString.toCharArray());
        return internQualifiedNames(result, false);
    }

    //TODO: remove once PDE API Tools has been adapted to also use java.util.Set, so that git history is preserved
    public static char[][][] internQualifiedNames(StringSet qualifiedStrings) {
        if (qualifiedStrings == null)
            return EmptyQualifiedNames;
        int length = qualifiedStrings.elementSize;
        if (length == 0)
            return EmptyQualifiedNames;

        char[][][] result = new char[length][][];
        String[] strings = qualifiedStrings.values;
        for (int i = 0, l = strings.length; i < l; i++)
            if (strings[i] != null)
                result[--length] = CharOperation.splitOn('/', strings[i].toCharArray());
        return internQualifiedNames(result, false);
    }

    /**
     * <strong>Note</strong>: this method may change order of the result data, the new array is always sorted.
     */
    public static char[][][] internQualifiedNames(char[][][] qualifiedNames) {
        return internQualifiedNames(qualifiedNames, false);
    }

    /**
     * Use a flyweight cache for the char arrays to avoid duplicated arrays with the same contents.
     * After calling this method, identity comparison on the array contents of the resulting array
     * will work for arrays with equal content.
     * <p>
     * <strong>Note</strong>: this method may change order of the result data, the new array is always sorted.
     * <p>
     * Optionally drops very common qualified names from the array to spare some bytes.
     *
     * @return a new array with interned elements.
     */
    public static char[][][] internQualifiedNames(char[][][] qualifiedNames, boolean keepWellKnown) {
        return internQualifiedNames(qualifiedNames, keepWellKnown, true);
    }

    static char[][][] internQualifiedNames(char[][][] qualifiedNames, boolean keepWellKnown, boolean doSort) {
        if (qualifiedNames == null)
            return EmptyQualifiedNames;
        int length = qualifiedNames.length;
        if (length == 0)
            return EmptyQualifiedNames;

        char[][][] keepers = new char[length][][];
        char[][] prev = null;
        boolean isSorted = true;
        int index = 0;

        next: for (int i = 0; i < length; i++) {
            char[][] qualifiedName = qualifiedNames[i];
            int qLength = qualifiedName.length;
            for (int j = 0, m = WellKnownQualifiedNames.length; j < m; j++) {
                char[][] wellKnownName = WellKnownQualifiedNames[j];
                if (qLength > wellKnownName.length)
                    break; // all remaining well known names are shorter
                if (CharOperation.equals(qualifiedName, wellKnownName)) {
                    if (keepWellKnown) {
                        // This code is duplicated to encourage the JIT to inline more stuff
                        if (doSort && isSorted) {
                            if (prev != null && SortedCharArrays.compareCharCharArray(prev, qualifiedName) > 0) {
                                isSorted = false;
                            }
                            prev = qualifiedName;
                        }
                        keepers[index++] = wellKnownName;
                    }
                    continue next;
                }
            }

            // InternedQualifiedNames[0] is for the rest (> 7 & 1)
            // InternedQualifiedNames[1] is for size 2...
            // InternedQualifiedNames[6] is for size 7
            QualifiedNameSet internedNames = InternedQualifiedNames[qLength <= MaxQualifiedNames ? qLength - 1 : 0];
            qualifiedName = internSimpleNames(qualifiedName, false, false);
            // This code is duplicated to encourage the JIT to inline more stuff
            if (doSort && isSorted) {
                if (prev != null && SortedCharArrays.compareCharCharArray(prev, qualifiedName) > 0) {
                    isSorted = false;
                }
                prev = qualifiedName;
            }
            keepers[index++] = internedNames.add(qualifiedName);
        }
        if (length > index) {
            if (index == 0)
                return EmptyQualifiedNames;
            System.arraycopy(keepers, 0, keepers = new char[index][][], 0, index);
        }
        if (doSort && !isSorted) {
            Arrays.sort(keepers, SortedCharArrays.CHAR_CHAR_ARR_COMPARATOR);
        }
        return keepers;
    }

    /**
     * @deprecated
     */
    public static char[][] internSimpleNames(Set<String> simpleStrings) {
        return internSimpleNames(simpleStrings, true);
    }

    // TODO: remove once ReferenceCollection.internSimpleNames(StringSet, boolean) is adapted to use java.util.Set, so that git history is preserved
    public static char[][] internSimpleNames(Set<String> simpleStrings, boolean removeWellKnown) {
        if (simpleStrings == null)
            return EmptySimpleNames;
        int length = simpleStrings.size();
        if (length == 0)
            return EmptySimpleNames;

        char[][] result = new char[length][];
        for (String simpleString : simpleStrings)
            if (simpleString != null)
                result[--length] = simpleString.toCharArray();
        return internSimpleNames(result, removeWellKnown);
    }

    //TODO: adjust to use java.util.Set once PDE API Tools have been adapted to use the set version, so that git history is preserved
    public static char[][] internSimpleNames(StringSet simpleStrings, boolean removeWellKnown) {
        if (simpleStrings == null)
            return EmptySimpleNames;
        int length = simpleStrings.elementSize;
        if (length == 0)
            return EmptySimpleNames;

        char[][] result = new char[length][];
        String[] strings = simpleStrings.values;
        for (int i = 0, l = strings.length; i < l; i++)
            if (strings[i] != null)
                result[--length] = strings[i].toCharArray();
        return internSimpleNames(result, removeWellKnown);
    }

    /**
     * Use a flyweight cache for the char arrays to avoid duplicated arrays with the same contents.
     * After calling this method, identity comparison on the array contents of the resulting array
     * will work for arrays with equal content.
     * <p>
     * <strong>Note</strong>: this method may change order of the result data, the new array is always sorted.
     * <p>
     * Optionally drops very common qualified names from the array to spare some bytes.
     *
     * @return a new array with interned elements.
     */
    public static char[][] internSimpleNames(char[][] simpleNames, boolean removeWellKnown) {
        return internSimpleNames(simpleNames, removeWellKnown, true);
    }

    static char[][] internSimpleNames(char[][] simpleNames, boolean removeWellKnown, boolean doSort) {
        if (simpleNames == null)
            return EmptySimpleNames;
        int length = simpleNames.length;
        if (length == 0)
            return EmptySimpleNames;

        char[][] keepers = new char[length][];
        char[] prev = null;
        boolean isSorted = true;
        int index = 0;
        next: for (int i = 0; i < length; i++) {
            char[] name = simpleNames[i];
            int sLength = name.length;
            for (int j = 0, m = WellKnownSimpleNames.length; j < m; j++) {
                char[] wellKnownName = WellKnownSimpleNames[j];
                if (sLength > wellKnownName.length)
                    break; // all remaining well known names are shorter
                if (CharOperation.equals(name, wellKnownName)) {
                    if (!removeWellKnown) {
                        keepers[index++] = wellKnownName;
                        // This code is duplicated to encourage the JIT to inline more stuff
                        if (doSort && isSorted) {
                            if (prev != null && SortedCharArrays.compareCharArray(prev, name) > 0) {
                                isSorted = false;
                            }
                            prev = name;
                        }
                    }
                    continue next;
                }
            }

            // InternedSimpleNames[0] is for the rest (> 29)
            // InternedSimpleNames[1] is for size 1...
            // InternedSimpleNames[29] is for size 29
            NameSet internedNames = InternedSimpleNames[sLength < MaxSimpleNames ? sLength : 0];
            keepers[index++] = internedNames.add(name);
            // This code is duplicated to encourage the JIT to inline more stuff
            if (doSort && isSorted) {
                if (prev != null && SortedCharArrays.compareCharArray(prev, name) > 0) {
                    isSorted = false;
                }
                prev = name;
            }
        }
        if (length > index) {
            if (index == 0)
                return EmptySimpleNames;
            System.arraycopy(keepers, 0, keepers = new char[index][], 0, index);
        }
        if (doSort && !isSorted) {
            Arrays.sort(keepers, SortedCharArrays.CHAR_ARR_COMPARATOR);
        }
        return keepers;
    }

    // DEBUG code below
    public static boolean REFERENCE_COLLECTION_DEBUG = false;

    private void assertIncludes(boolean expectation, char[] simpleName) {
        if (expectation != debugIncludes(simpleName)) {
            String message = "Mismatch: " + String.valueOf(simpleName) + (expectation ? " should not " : " should ") //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    + " be included in " //$NON-NLS-1$
                    + Arrays.asList(CharOperation.toStrings(this.simpleNameReferences));
            throw new IllegalStateException(message);
        }
    }

    private void assertIncludes(boolean expectation, char[][] qualifiedName) {
        if (expectation != debugIncludes(qualifiedName)) {
            String message = "Mismatch: " + CharOperation.toString(qualifiedName) //$NON-NLS-1$
                    + (expectation ? " should not " : " should ") + " be included in " //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    + qualifiedNamesToString(this.qualifiedNameReferences);
            throw new IllegalStateException(message);
        }
    }

    private void assertIncludes(boolean expectation, char[][][] qualifiedNames, char[][] simpleNames,
            char[][] rootNames) {
        if (expectation != debugIncludes(qualifiedNames, simpleNames, rootNames)) {
            String message = String.format(
                    "Mismatched includes(..): ReferenceCollection([%s], %s, %s).includes([%s], %s, %s)", //$NON-NLS-1$
                    qualifiedNamesToString(this.qualifiedNameReferences),
                    Arrays.toString(CharOperation.toStrings(this.simpleNameReferences)),
                    Arrays.toString(CharOperation.toStrings(this.rootReferences)),
                    qualifiedNamesToString(qualifiedNames), Arrays.toString(CharOperation.toStrings(simpleNames)),
                    Arrays.toString(CharOperation.toStrings(rootNames)));
            throw new IllegalStateException(message);
        }
    }

    private boolean debugIncludes(char[][][] qualifiedNames, char[][] simpleNames, char[][] rootNames) {
        // if either collection of names is null, it means it contained a well known name so we know it already has a match
        if (rootNames != null) {
            boolean foundRoot = false;
            for (int i = 0, l = rootNames.length; !foundRoot && i < l; i++)
                foundRoot = debugInsideRoot(rootNames[i]);
            if (!foundRoot)
                return false;
        }
        if (simpleNames == null || qualifiedNames == null) {
            if (simpleNames == null && qualifiedNames == null) {
                if (JavaBuilder.DEBUG)
                    System.out.println("Found well known match"); //$NON-NLS-1$
                return true;
            } else if (qualifiedNames == null) {
                for (int i = 0, l = simpleNames.length; i < l; i++) {
                    if (debugIncludes(simpleNames[i])) {
                        if (JavaBuilder.DEBUG)
                            System.out
                                    .println("Found match in well known package to " + new String(simpleNames[i])); //$NON-NLS-1$
                        return true;
                    }
                }
            } else {
                for (int i = 0, l = qualifiedNames.length; i < l; i++) {
                    char[][] qualifiedName = qualifiedNames[i];
                    if (qualifiedName.length == 1 ? debugIncludes(qualifiedName[0])
                            : debugIncludes(qualifiedName)) {
                        if (JavaBuilder.DEBUG)
                            System.out
                                    .println("Found well known match in " + CharOperation.toString(qualifiedName)); //$NON-NLS-1$
                        return true;
                    }
                }
            }
            return false;
        }

        int sLength = simpleNames.length;
        int qLength = qualifiedNames.length;
        if (sLength <= qLength) {
            for (int i = 0; i < sLength; i++) {
                if (debugIncludes(simpleNames[i])) {
                    for (int j = 0; j < qLength; j++) {
                        char[][] qualifiedName = qualifiedNames[j];
                        if (qualifiedName.length == 1 ? debugIncludes(qualifiedName[0])
                                : debugIncludes(qualifiedName)) {
                            if (JavaBuilder.DEBUG)
                                System.out.println("Found match in " + CharOperation.toString(qualifiedName) //$NON-NLS-1$
                                        + " to " + new String(simpleNames[i])); //$NON-NLS-1$
                            return true;
                        }
                    }
                    return false;
                }
            }
        } else {
            for (int i = 0; i < qLength; i++) {
                char[][] qualifiedName = qualifiedNames[i];
                if (qualifiedName.length == 1 ? debugIncludes(qualifiedName[0]) : debugIncludes(qualifiedName)) {
                    for (int j = 0; j < sLength; j++) {
                        if (debugIncludes(simpleNames[j])) {
                            if (JavaBuilder.DEBUG)
                                System.out.println("Found match in " + CharOperation.toString(qualifiedName) //$NON-NLS-1$
                                        + " to " + new String(simpleNames[j])); //$NON-NLS-1$
                            return true;
                        }
                    }
                    return false;
                }
            }
        }
        return false;
    }

    private boolean debugInsideRoot(char[] rootName) {
        for (int i = 0, l = this.rootReferences.length; i < l; i++)
            if (rootName == this.rootReferences[i])
                return true;
        return false;
    }

    private boolean debugIncludes(char[] simpleName) {
        for (int i = 0, l = this.simpleNameReferences.length; i < l; i++)
            if (simpleName == this.simpleNameReferences[i])
                return true;
        return false;
    }

    private boolean debugIncludes(char[][] qualifiedName) {
        for (int i = 0, l = this.qualifiedNameReferences.length; i < l; i++)
            if (qualifiedName == this.qualifiedNameReferences[i])
                return true;
        return false;
    }

}