All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.pmd.lang.java.symbols.JClassSymbol Maven / Gradle / Ivy

There is a newer version: 7.7.0
Show newest version
/*
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */


package net.sourceforge.pmd.lang.java.symbols;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Modifier;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.pcollections.HashTreePSet;
import org.pcollections.PSet;

import net.sourceforge.pmd.lang.java.ast.ASTTypeDeclaration;
import net.sourceforge.pmd.lang.java.symbols.SymbolicValue.SymAnnot;
import net.sourceforge.pmd.lang.java.symbols.SymbolicValue.SymEnum;
import net.sourceforge.pmd.lang.java.types.JArrayType;
import net.sourceforge.pmd.lang.java.types.JClassType;
import net.sourceforge.pmd.lang.java.types.JPrimitiveType;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
import net.sourceforge.pmd.lang.java.types.Substitution;


/**
 * Abstraction over a {@link Class} instance. This is not a type, it's
 * the *declaration* of a type. For example, a class symbol representing
 * a generic class can provide access to the formal type parameters, but
 * the symbol does not represent a specific parametrization of a type.
 *
 * 

Class symbols represent the full range of types represented by {@link Class}: * classes, interfaces, arrays, and primitives. This excludes type variables, * intersection types, parameterized types, wildcard types, etc., which are only * compile-time constructs. * *

Class symbols are used to back {@link JClassType}, {@link JArrayType}, * and {@link JPrimitiveType}. See {@link JTypeMirror#getSymbol()}. * * @since 7.0.0 */ public interface JClassSymbol extends JTypeDeclSymbol, JTypeParameterOwnerSymbol, BoundToNode { /** * Returns the binary name of this type, as specified by the JLS: * the JLS. * For array types this returns the binary name of the component followed by "[]". * This differs from {@link Class#getName()}, which for array types outputs an * internal name. * *

For example: *

{@code
     * int.class.getName() == "int"
     * int[].class.getName() == "[I"
     * String.class.getName() == "java.lang.String"
     * String[].class.getName() == "[Ljava.lang.String;"
     * }
* whereas *
{@code
     * symbolOf(int.class).getBinaryName() == "int"
     * symbolOf(int[].class).getBinaryName() == "int[]"
     * symbolOf(String.class).getBinaryName() == "java.lang.String"
     * symbolOf(String[].class).getBinaryName() == "java.lang.String[]"
     * }
*/ @NonNull String getBinaryName(); /** * Returns the simple name of this class, as specified by * {@link Class#getCanonicalName()}. */ @Nullable String getCanonicalName(); /** * Returns the method or constructor this symbol is declared in, if * it represents a {@linkplain #isLocalClass() local class declaration}. * *

Notice, that this returns null also if this class is local to * a class or instance initializer. */ @Nullable JExecutableSymbol getEnclosingMethod(); @Override default JTypeParameterOwnerSymbol getEnclosingTypeParameterOwner() { JExecutableSymbol enclosingMethod = getEnclosingMethod(); return enclosingMethod != null ? enclosingMethod : getEnclosingClass(); } /** * Returns the member classes declared directly in this class. * * @see Class#getDeclaredClasses() */ List getDeclaredClasses(); /** Returns a class with the given name defined in this class. */ @Nullable default JClassSymbol getDeclaredClass(String name) { for (JClassSymbol klass : getDeclaredClasses()) { if (klass.nameEquals(name)) { return klass; } } return null; } /** * Returns the methods declared directly in this class. * This excludes bridges and other synthetic methods. * *

For an array type T[], to the difference of {@link Class}, * this method returns a one-element list with the {@link Object#clone()} * method, as if declared like so: {@code public final T[] clone() {...}}. * * @see Class#getDeclaredMethods() */ List getDeclaredMethods(); /** * Returns the constructors declared by this class. * This excludes synthetic constructors. * *

For an array type T[], and to the difference of {@link Class}, * this should return a one-element list with a constructor * having the same modifiers as the array type, and a single * {@code int} parameter. * * @see Class#getDeclaredConstructors() */ List getConstructors(); /** * Returns the fields declared directly in this class. * This excludes synthetic fields. * *

For arrays, and to the difference of {@link Class}, * this should return a one-element list with the * {@code public final int length} field. * * @see Class#getDeclaredFields() */ List getDeclaredFields(); /** Returns a field with the given name defined in this class. */ @Nullable default JFieldSymbol getDeclaredField(String name) { for (JFieldSymbol field : getDeclaredFields()) { if (field.nameEquals(name)) { return field; } } return null; } /** * Returns a list with all enum constants. If this symbol does * not represent an enum, returns an empty list. The returned list * is a subset of {@link #getDeclaredFields()}. The order of fields * denotes the normal order of enum constants. */ default @NonNull List getEnumConstants() { return Collections.emptyList(); } /** * Returns a list with all record components. If this symbol does * not represent a record, returns an empty list. The order of values * denotes the normal order of components. */ default @NonNull List getRecordComponents() { return Collections.emptyList(); } /** Returns the list of super interface types, under the given substitution. */ List getSuperInterfaceTypes(Substitution substitution); /** Returns the superclass type, under the given substitution. */ @Nullable JClassType getSuperclassType(Substitution substitution); /** * Returns the superclass symbol if it exists. Returns null if this * class represents the class {@link Object}, or a primitive type. * If this symbol is an interface, returns the symbol for {@link Object}. */ @Nullable JClassSymbol getSuperclass(); /** Returns the direct super-interfaces of this class or interface symbol. */ List getSuperInterfaces(); default boolean isAbstract() { return Modifier.isAbstract(getModifiers()); } /** Returns the component symbol, returns null if this is not an array. */ @Nullable JTypeDeclSymbol getArrayComponent(); boolean isArray(); boolean isPrimitive(); boolean isEnum(); boolean isRecord(); boolean isAnnotation(); boolean isLocalClass(); boolean isAnonymousClass(); /** * Return the simple names of all annotation attributes. If this * is not an annotation type, return an empty set. */ default PSet getAnnotationAttributeNames() { return HashTreePSet.empty(); } /** * Return the default value of the attribute if this is an annotation type * with a default. Return null if this is not an annotation type, if there * is no such attribute, or the attribute has no default value. If the name * is in the {@linkplain #getAnnotationAttributeNames() attribute name set}, * then the null return value can only mean that the attribute exists but has * no default value. * * @param attrName Attribute name */ default @Nullable SymbolicValue getDefaultAnnotationAttributeValue(String attrName) { if (!isAnnotation()) { return null; } for (JMethodSymbol m : getDeclaredMethods()) { if (m.nameEquals(attrName) && m.isAnnotationAttribute()) { return m.getDefaultAnnotationValue(); // nullable } } return null; } /** * Returns the retention policy of this annotation, if this is an * annotation symbol. Otherwise returns null. */ default @Nullable RetentionPolicy getAnnotationRetention() { if (!isAnnotation()) { return null; } return Optional.ofNullable(getDeclaredAnnotation(Retention.class)) .map(annot -> annot.getAttribute("value")) .filter(value -> value instanceof SymEnum) .map(value -> ((SymEnum) value).toEnum(RetentionPolicy.class)) .orElse(RetentionPolicy.CLASS); } /** * Return whether annotations of this annotation type apply to the * given construct, as per the {@link Target} annotation. Return * false if this is not an annotation. */ default boolean annotationAppliesTo(ElementType elementType) { if (!isAnnotation()) { return false; } SymAnnot target = getDeclaredAnnotation(Target.class); if (target == null) { // If an @Target meta-annotation is not present on an annotation type T, // then an annotation of type T may be written as a modifier // for any declaration except a type parameter declaration. return elementType != ElementType.TYPE_PARAMETER; } return target.attributeContains("value", elementType).isTrue(); } // todo isSealed + getPermittedSubclasses // (isNonSealed is not so useful I think) /** * This returns true if this is not an interface, primitive or array. */ default boolean isClass() { return !isInterface() && !isArray() && !isPrimitive(); } /** * Returns the toplevel class containing this class. If this is a * toplevel class, returns this. */ default @NonNull JClassSymbol getNestRoot() { JClassSymbol e = this; while (e.getEnclosingClass() != null) { e = e.getEnclosingClass(); } return e; } @Override default R acceptVisitor(SymbolVisitor visitor, P param) { return visitor.visitClass(this, param); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy