net.sourceforge.pmd.lang.java.ast.AccessNode Maven / Gradle / Ivy
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.ast;
import static net.sourceforge.pmd.lang.java.ast.JModifier.STRICTFP;
import java.util.Set;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.ast.NodeStream;
/**
* A node that owns a {@linkplain ASTModifierList modifier list}.
*
* {@link AccessNode} methods take into account the syntactic context of the
* declaration, e.g. {@link #isPublic()} will always return true for a field
* declared inside an interface, regardless of whether the {@code public}
* modifier was specified explicitly or not. If you want to know whether
* the modifier was explicitly stated, use {@link #hasExplicitModifiers(JModifier, JModifier...)}.
*
* TODO make modifiers accessible from XPath
* * Ideally we'd have two attributes, eg @EffectiveModifiers and @ExplicitModifiers,
* which would each return a sequence, eg ("public", "static", "final")
* * Ideally we'd have a way to add attributes that are not necessarily
* getters on the node. It makes no sense in the Java API to expose
* those getters on the node, it's more orthogonal to query getModifiers() directly.
*
* TODO rename to ModifierOwner, kept out from PR to reduce diff
*/
public interface AccessNode extends Annotatable {
@Override
default NodeStream getDeclaredAnnotations() {
return getModifiers().children(ASTAnnotation.class);
}
/**
* Returns the node representing the modifier list of this node.
*/
default @NonNull ASTModifierList getModifiers() {
return firstChild(ASTModifierList.class);
}
/**
* Returns the visibility corresponding to the {@link ASTModifierList#getEffectiveModifiers() effective modifiers}.
* Eg a public method will have visibility {@link Visibility#V_PUBLIC public},
* a local class will have visibility {@link Visibility#V_LOCAL local}.
* There cannot be any conflict with {@link #hasModifiers(JModifier, JModifier...)}} on
* well-formed code (e.g. for any {@code n}, {@code (n.getVisibility() == V_PROTECTED) ==
* n.hasModifiers(PROTECTED)})
*
* TODO a public method of a private class can be considered to be private
* we could probably add another method later on that takes this into account
*/
default Visibility getVisibility() {
Set effective = getModifiers().getEffectiveModifiers();
if (effective.contains(JModifier.PUBLIC)) {
return Visibility.V_PUBLIC;
} else if (effective.contains(JModifier.PROTECTED)) {
return Visibility.V_PROTECTED;
} else if (effective.contains(JModifier.PRIVATE)) {
return Visibility.V_PRIVATE;
} else {
return Visibility.V_PACKAGE;
}
}
/**
* Returns the "effective" visibility of a member. This is the minimum
* visibility of its enclosing type declarations. For example, a public
* method of a private class is "effectively private".
*
* Local declarations keep local visibility, eg a local variable
* somewhere in an anonymous class doesn't get anonymous visibility.
*/
default Visibility getEffectiveVisibility() {
Visibility minv = getVisibility();
if (minv == Visibility.V_LOCAL) {
return minv;
}
for (ASTAnyTypeDeclaration enclosing : ancestors(ASTAnyTypeDeclaration.class)) {
minv = Visibility.min(minv, enclosing.getVisibility());
if (minv == Visibility.V_LOCAL) {
return minv;
}
}
return minv;
}
/**
* Returns true if this node has all the given modifiers
* either explicitly written or inferred through context.
*/
default boolean hasModifiers(JModifier mod1, JModifier... mod) {
return getModifiers().hasAll(mod1, mod);
}
/**
* Returns true if this node has all the given modifiers
* explicitly written in the source.
*/
default boolean hasExplicitModifiers(JModifier mod1, JModifier... mod) {
return getModifiers().hasAllExplicitly(mod1, mod);
}
// TODO remove all those, kept only for compatibility with rules
// these are about effective modifiers
@Deprecated
default boolean isFinal() {
return hasModifiers(JModifier.FINAL);
}
@Deprecated
default boolean isAbstract() {
return hasModifiers(JModifier.ABSTRACT);
}
@Deprecated
default boolean isStrictfp() {
return hasModifiers(STRICTFP);
}
@Deprecated
default boolean isSynchronized() {
return hasModifiers(JModifier.SYNCHRONIZED);
}
@Deprecated
default boolean isNative() {
return hasModifiers(JModifier.NATIVE);
}
@Deprecated
default boolean isStatic() {
return hasModifiers(JModifier.STATIC);
}
@Deprecated
default boolean isVolatile() {
return hasModifiers(JModifier.VOLATILE);
}
@Deprecated
default boolean isTransient() {
return hasModifiers(JModifier.TRANSIENT);
}
// these are about visibility
@Deprecated
default boolean isPrivate() {
return getVisibility() == Visibility.V_PRIVATE;
}
@Deprecated
default boolean isPublic() {
return getVisibility() == Visibility.V_PUBLIC;
}
@Deprecated
default boolean isProtected() {
return getVisibility() == Visibility.V_PROTECTED;
}
@Deprecated
default boolean isPackagePrivate() {
return getVisibility() == Visibility.V_PACKAGE;
}
// these are about explicit modifiers
@Deprecated
default boolean isSyntacticallyAbstract() {
return hasExplicitModifiers(JModifier.ABSTRACT);
}
@Deprecated
default boolean isSyntacticallyPublic() {
return hasExplicitModifiers(JModifier.PUBLIC);
}
@Deprecated
default boolean isSyntacticallyStatic() {
return hasExplicitModifiers(JModifier.STATIC);
}
@Deprecated
default boolean isSyntacticallyFinal() {
return hasExplicitModifiers(JModifier.FINAL);
}
/**
* Represents the visibility of a declaration.
*
*
The ordering of the constants encodes a "contains" relationship,
* ie, given two visibilities {@code v1} and {@code v2}, {@code v1 < v2}
* means that {@code v2} is strictly more permissive than {@code v1}.
*/
enum Visibility {
// Note: constants are prefixed with "V_" to avoid conflicts with JModifier
/** Special visibility of anonymous classes, even more restricted than local. */
V_ANONYMOUS("anonymous"),
/** Confined to a local scope, eg method parameters, local variables, local classes. */
V_LOCAL("local"),
/** File-private. Corresponds to modifier {@link JModifier#PRIVATE}. */
V_PRIVATE("private"),
/** Package-private. */
V_PACKAGE("package"),
/** Package-private + visible to subclasses. Corresponds to modifier {@link JModifier#PROTECTED}. */
V_PROTECTED("protected"),
/** Visible everywhere. Corresponds to modifier {@link JModifier#PUBLIC}. */
V_PUBLIC("public");
private final String myName;
Visibility(String name) {
this.myName = name;
}
@Override
public String toString() {
return myName;
}
/**
* Returns true if this visibility is greater than or equal to
* the parameter.
*/
public boolean isAtLeast(Visibility other) {
return this.compareTo(other) >= 0;
}
/**
* Returns true if this visibility is lower than or equal to the
* parameter.
*/
public boolean isAtMost(Visibility other) {
return this.compareTo(other) <= 0;
}
/**
* The minimum of both visibilities.
*/
static Visibility min(Visibility v1, Visibility v2) {
return v1.compareTo(v2) <= 0 ? v1 : v2;
}
}
}