Skip to content

Java: RefType.getAnAncestor() is error-prone when supertype is parameterized type with Object as type argument #5595

@Marcono1234

Description

@Marcono1234

The predicate RefType.getAnAcestor() is error-prone when one of the supertypes is a generic type parameterized with Object as type argument. In that case getASupertype() and getAnAcestor() return all types which have a lower bound (but are not actually relevant), e.g.:

import java

from RefType t
where t.hasName("ObjectToStringComparator")
select t, t.getAnAncestor()

Query Console link

Result hierarchy (click to expand)
  • ObjectToStringComparator
    • Serializable
    • Object
    • Comparator<Object>
      • Comparator<>
      • Comparator<? super Boolean>
      • Comparator<? super Callable<Integer>>
      • Comparator<? super CharSequence>
      • Comparator<? super Class<?>>
      • Comparator<? super Diff<?>>
      • Comparator<? super Double>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super E>
      • Comparator<? super Field>
      • Comparator<? super Format>
      • Comparator<? super Hobby>
      • Comparator<? super ImmutablePair<Integer,Integer>>
      • Comparator<? super ImmutableTriple<Integer,Integer,Integer>>
      • Comparator<? super Integer>
      • Comparator<? super K>
      • Comparator<? super K>
      • Comparator<? super K>
      • Comparator<? super K>
      • Comparator<? super L>
      • Comparator<? super Locale>
      • Comparator<? super Long>
      • Comparator<? super Method>
      • Comparator<? super MethodDescriptor>
      • Comparator<? super Method[]>
      • Comparator<? super O>
      • Comparator<? super O>
      • Comparator<? super O>
      • Comparator<? super O>
      • Comparator<? super Object>
      • Comparator<? super Pair<String,Object>>
      • Comparator<? super Rule>
      • Comparator<? super StrategyAndWidth>
      • Comparator<? super String>
      • Comparator<? super Student>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super T>
      • Comparator<? super Thing>
      • Comparator<? super Thread>
      • Comparator<? super ThreadGroup>
      • Comparator<? super Throwable>
      • Comparator<? super Token>
      • Comparator<? super Traffic>
      • Comparator<? super Transaction>
      • Comparator<? super TypeVariable<Class<T>>>
      • Comparator<? super U>
      • Comparator<? super U>
      • Comparator<? super V>
      • Comparator<? super VetoableChangeListener>
      • Comparator<?>
      • Object

This is most likely not the desired behavior. Therefore it might be good to deprecate getAnAncestor() and instead add a predicate getASourceAncestor() (which also deliberately does not have this as result):

/**
 * Gets a source ancestor of this type, that is, a direct supertype or a direct supertype of the
 * source declaration of a supertype, recursively.
 */
RefType getASourceAncestor() {
  // Checking for source declaration is necessary, otherwise class `Generic<T>` would have `Generic<>` (raw),
  // `Generic<?>` and `Generic<? super T>` as supertypes
  result = getASupertype() and result.getSourceDeclaration() != getSourceDeclaration()
  or result = getASourceAncestor(getASupertype().getSourceDeclaration())
}

As seen here, it is necessary to check result.getSourceDeclaration() != getSourceDeclaration() since RefType is currently missing a predicate for getting a supertype declared in source (or the implicit Object); this is slightly related to #3818.
Ideally such a predicate would have the name getASourceSupertype(), however that name is already taken. A better fitting name for the existing predicate would probably be getASupertypeSource() / getASupertypeSourceDeclaration(), since that is what it actually does: "Gets the source declaration of a direct supertype of this type"

Metadata

Metadata

Assignees

No one assigned

    Labels

    JavaquestionFurther information is requested

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions