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

com.puppycrawl.tools.checkstyle.utils.ScopeUtil Maven / Gradle / Ivy

Go to download

Checkstyle is a development tool to help programmers write Java code that adheres to a coding standard

There is a newer version: 10.20.1
Show newest version
///////////////////////////////////////////////////////////////////////////////////////////////
// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
// Copyright (C) 2001-2024 the original author or authors.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
///////////////////////////////////////////////////////////////////////////////////////////////

package com.puppycrawl.tools.checkstyle.utils;

import java.util.Optional;

import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.Scope;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;

/**
 * Contains utility methods for working on scope.
 *
 */
public final class ScopeUtil {

    /** Prevent instantiation. */
    private ScopeUtil() {
    }

    /**
     * Returns the {@code Scope} explicitly specified by the modifier set.
     * Returns {@code null} if there are no modifiers.
     *
     * @param aMods root node of a modifier set
     * @return a {@code Scope} value or {@code null}
     */
    public static Scope getDeclaredScopeFromMods(DetailAST aMods) {
        Scope result = null;
        for (DetailAST token = aMods.getFirstChild(); token != null;
             token = token.getNextSibling()) {
            switch (token.getType()) {
                case TokenTypes.LITERAL_PUBLIC:
                    result = Scope.PUBLIC;
                    break;
                case TokenTypes.LITERAL_PROTECTED:
                    result = Scope.PROTECTED;
                    break;
                case TokenTypes.LITERAL_PRIVATE:
                    result = Scope.PRIVATE;
                    break;
                default:
                    break;
            }
        }
        return result;
    }

    /**
     * Returns the {@code Scope} for a given {@code DetailAST}.
     *
     * @param ast the DetailAST to examine
     * @return a {@code Scope} value
     */
    public static Scope getScope(DetailAST ast) {
        return Optional.ofNullable(ast.findFirstToken(TokenTypes.MODIFIERS))
                .map(ScopeUtil::getDeclaredScopeFromMods)
                .orElseGet(() -> getDefaultScope(ast));
    }

    /**
     * Returns the {@code Scope} specified by the modifier set. If no modifiers are present,
     * the default scope is used.
     *
     * @param aMods root node of a modifier set
     * @return a {@code Scope} value
     * @see #getDefaultScope(DetailAST)
     */
    public static Scope getScopeFromMods(DetailAST aMods) {
        return Optional.ofNullable(getDeclaredScopeFromMods(aMods))
                .orElseGet(() -> getDefaultScope(aMods));
    }

    /**
     * Returns the default {@code Scope} for a {@code DetailAST}.
     * 

The following rules are taken into account:

*
    *
  • enum constants are public
  • *
  • enum constructors are private
  • *
  • interface members are public
  • *
  • everything else is package private
  • *
* * @param ast DetailAST to process * @return a {@code Scope} value */ private static Scope getDefaultScope(DetailAST ast) { final Scope result; if (isInEnumBlock(ast)) { if (ast.getType() == TokenTypes.ENUM_CONSTANT_DEF) { result = Scope.PUBLIC; } else if (ast.getType() == TokenTypes.CTOR_DEF) { result = Scope.PRIVATE; } else { result = Scope.PACKAGE; } } else if (isInInterfaceOrAnnotationBlock(ast)) { result = Scope.PUBLIC; } else { result = Scope.PACKAGE; } return result; } /** * Returns the scope of the surrounding "block". * * @param node the node to return the scope for * @return the Scope of the surrounding block */ public static Scope getSurroundingScope(DetailAST node) { Scope returnValue = null; for (DetailAST token = node; token != null; token = token.getParent()) { final int type = token.getType(); if (TokenUtil.isTypeDeclaration(type)) { final Scope tokenScope = getScope(token); if (returnValue == null || returnValue.isIn(tokenScope)) { returnValue = tokenScope; } } else if (type == TokenTypes.LITERAL_NEW) { returnValue = Scope.ANONINNER; // because Scope.ANONINNER is not in any other Scope break; } } return returnValue; } /** * Returns whether a node is directly contained within a class block. * * @param node the node to check if directly contained within a class block. * @return a {@code boolean} value */ public static boolean isInClassBlock(DetailAST node) { return isInBlockOf(node, TokenTypes.CLASS_DEF); } /** * Returns whether a node is directly contained within a record block. * * @param node the node to check if directly contained within a record block. * @return a {@code boolean} value */ public static boolean isInRecordBlock(DetailAST node) { return isInBlockOf(node, TokenTypes.RECORD_DEF); } /** * Returns whether a node is directly contained within an interface block. * * @param node the node to check if directly contained within an interface block. * @return a {@code boolean} value */ public static boolean isInInterfaceBlock(DetailAST node) { return isInBlockOf(node, TokenTypes.INTERFACE_DEF); } /** * Returns whether a node is directly contained within an annotation block. * * @param node the node to check if directly contained within an annotation block. * @return a {@code boolean} value */ public static boolean isInAnnotationBlock(DetailAST node) { return isInBlockOf(node, TokenTypes.ANNOTATION_DEF); } /** * Returns whether a node is directly contained within a specified block. * * @param node the node to check if directly contained within a specified block. * @param tokenType type of token. * @return a {@code boolean} value */ private static boolean isInBlockOf(DetailAST node, int tokenType) { boolean returnValue = false; // Loop up looking for a containing interface block for (DetailAST token = node.getParent(); token != null && !returnValue; token = token.getParent()) { if (token.getType() == tokenType) { returnValue = true; } else if (token.getType() == TokenTypes.LITERAL_NEW || TokenUtil.isTypeDeclaration(token.getType())) { break; } } return returnValue; } /** * Returns whether a node is directly contained within an interface or * annotation block. * * @param node the node to check if directly contained within an interface * or annotation block. * @return a {@code boolean} value */ public static boolean isInInterfaceOrAnnotationBlock(DetailAST node) { return isInInterfaceBlock(node) || isInAnnotationBlock(node); } /** * Returns whether a node is directly contained within an enum block. * * @param node the node to check if directly contained within an enum block. * @return a {@code boolean} value */ public static boolean isInEnumBlock(DetailAST node) { boolean returnValue = false; // Loop up looking for a containing interface block for (DetailAST token = node.getParent(); token != null; token = token.getParent()) { if (TokenUtil.isOfType(token, TokenTypes.INTERFACE_DEF, TokenTypes.ANNOTATION_DEF, TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.ENUM_DEF)) { returnValue = token.getType() == TokenTypes.ENUM_DEF; break; } } return returnValue; } /** * Returns whether the scope of a node is restricted to a code block. * A code block is a method or constructor body, an initializer block, or lambda body. * * @param node the node to check * @return a {@code boolean} value */ public static boolean isInCodeBlock(DetailAST node) { boolean returnValue = false; final int[] tokenTypes = { TokenTypes.METHOD_DEF, TokenTypes.CTOR_DEF, TokenTypes.INSTANCE_INIT, TokenTypes.STATIC_INIT, TokenTypes.LAMBDA, TokenTypes.COMPACT_CTOR_DEF, }; // Loop up looking for a containing code block for (DetailAST token = node.getParent(); token != null; token = token.getParent()) { if (TokenUtil.isOfType(token, tokenTypes)) { returnValue = true; break; } } return returnValue; } /** * Returns whether a node is contained in the outermost type block. * * @param node the node to check * @return a {@code boolean} value */ public static boolean isOuterMostType(DetailAST node) { boolean returnValue = true; for (DetailAST parent = node.getParent(); parent != null; parent = parent.getParent()) { if (TokenUtil.isTypeDeclaration(parent.getType())) { returnValue = false; break; } } return returnValue; } /** * Determines whether a node is a local variable definition. * I.e. if it is declared in a code block, a for initializer, * or a catch parameter. * * @param node the node to check. * @return whether aAST is a local variable definition. */ public static boolean isLocalVariableDef(DetailAST node) { final boolean localVariableDef; // variable declaration? if (node.getType() == TokenTypes.VARIABLE_DEF) { final DetailAST parent = node.getParent(); localVariableDef = TokenUtil.isOfType(parent, TokenTypes.SLIST, TokenTypes.FOR_INIT, TokenTypes.FOR_EACH_CLAUSE); } else if (node.getType() == TokenTypes.RESOURCE) { localVariableDef = node.getChildCount() > 1; } // catch parameter? else if (node.getType() == TokenTypes.PARAMETER_DEF) { final DetailAST parent = node.getParent(); localVariableDef = parent.getType() == TokenTypes.LITERAL_CATCH; } else { localVariableDef = false; } return localVariableDef; } /** * Determines whether a node is a class field definition. * I.e. if a variable is not declared in a code block, a for initializer, * or a catch parameter. * * @param node the node to check. * @return whether a node is a class field definition. */ public static boolean isClassFieldDef(DetailAST node) { return node.getType() == TokenTypes.VARIABLE_DEF && !isLocalVariableDef(node); } /** * Checks whether ast node is in a specific scope. * * @param ast the node to check. * @param scope a {@code Scope} value. * @return true if the ast node is in the scope. */ public static boolean isInScope(DetailAST ast, Scope scope) { final Scope surroundingScopeOfAstToken = getSurroundingScope(ast); return surroundingScopeOfAstToken == scope; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy