Coverage Report - com.puppycrawl.tools.checkstyle.utils.ScopeUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
ScopeUtils
100%
86/86
100%
102/102
4.538
 
 1  
 ////////////////////////////////////////////////////////////////////////////////
 2  
 // checkstyle: Checks Java source code for adherence to a set of rules.
 3  
 // Copyright (C) 2001-2017 the original author or authors.
 4  
 //
 5  
 // This library is free software; you can redistribute it and/or
 6  
 // modify it under the terms of the GNU Lesser General Public
 7  
 // License as published by the Free Software Foundation; either
 8  
 // version 2.1 of the License, or (at your option) any later version.
 9  
 //
 10  
 // This library is distributed in the hope that it will be useful,
 11  
 // but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 13  
 // Lesser General Public License for more details.
 14  
 //
 15  
 // You should have received a copy of the GNU Lesser General Public
 16  
 // License along with this library; if not, write to the Free Software
 17  
 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 18  
 ////////////////////////////////////////////////////////////////////////////////
 19  
 
 20  
 package com.puppycrawl.tools.checkstyle.utils;
 21  
 
 22  
 import antlr.collections.AST;
 23  
 import com.puppycrawl.tools.checkstyle.api.DetailAST;
 24  
 import com.puppycrawl.tools.checkstyle.api.Scope;
 25  
 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
 26  
 
 27  
 /**
 28  
  * Contains utility methods for working on scope.
 29  
  *
 30  
  * @author Oliver Burn
 31  
  */
 32  
 public final class ScopeUtils {
 33  
     /** Prevent instantiation. */
 34  1
     private ScopeUtils() {
 35  1
     }
 36  
 
 37  
     /**
 38  
      * Returns the Scope specified by the modifier set.
 39  
      *
 40  
      * @param aMods root node of a modifier set
 41  
      * @return a {@code Scope} value
 42  
      */
 43  
     public static Scope getScopeFromMods(DetailAST aMods) {
 44  
         // default scope
 45  5506
         Scope returnValue = Scope.PACKAGE;
 46  5506
         for (AST token = aMods.getFirstChild(); token != null
 47  9740
                 && returnValue == Scope.PACKAGE;
 48  4234
                 token = token.getNextSibling()) {
 49  4234
             if ("public".equals(token.getText())) {
 50  3106
                 returnValue = Scope.PUBLIC;
 51  
             }
 52  1128
             else if ("protected".equals(token.getText())) {
 53  278
                 returnValue = Scope.PROTECTED;
 54  
             }
 55  850
             else if ("private".equals(token.getText())) {
 56  537
                 returnValue = Scope.PRIVATE;
 57  
             }
 58  
         }
 59  5506
         return returnValue;
 60  
     }
 61  
 
 62  
     /**
 63  
      * Returns the scope of the surrounding "block".
 64  
      * @param node the node to return the scope for
 65  
      * @return the Scope of the surrounding block
 66  
      */
 67  
     public static Scope getSurroundingScope(DetailAST node) {
 68  3535
         Scope returnValue = null;
 69  3535
         for (DetailAST token = node.getParent();
 70  17966
              token != null;
 71  14431
              token = token.getParent()) {
 72  14521
             final int type = token.getType();
 73  14521
             if (type == TokenTypes.CLASS_DEF
 74  
                 || type == TokenTypes.INTERFACE_DEF
 75  
                 || type == TokenTypes.ANNOTATION_DEF
 76  
                 || type == TokenTypes.ENUM_DEF) {
 77  3829
                 final DetailAST mods =
 78  3829
                     token.findFirstToken(TokenTypes.MODIFIERS);
 79  3829
                 final Scope modScope = getScopeFromMods(mods);
 80  3829
                 if (returnValue == null || returnValue.isIn(modScope)) {
 81  3540
                     returnValue = modScope;
 82  
                 }
 83  3829
             }
 84  10692
             else if (type == TokenTypes.LITERAL_NEW) {
 85  90
                 returnValue = Scope.ANONINNER;
 86  
                 // because Scope.ANONINNER is not in any other Scope
 87  90
                 break;
 88  
             }
 89  
         }
 90  
 
 91  3535
         return returnValue;
 92  
     }
 93  
 
 94  
     /**
 95  
      * Returns whether a node is directly contained within an interface block.
 96  
      *
 97  
      * @param node the node to check if directly contained within an interface block.
 98  
      * @return a {@code boolean} value
 99  
      */
 100  
     public static boolean isInInterfaceBlock(DetailAST node) {
 101  4147
         return isInBlockOf(node, TokenTypes.INTERFACE_DEF);
 102  
     }
 103  
 
 104  
     /**
 105  
      * Returns whether a node is directly contained within an annotation block.
 106  
      *
 107  
      * @param node the node to check if directly contained within an annotation block.
 108  
      * @return a {@code boolean} value
 109  
      */
 110  
     public static boolean isInAnnotationBlock(DetailAST node) {
 111  4416
         return isInBlockOf(node, TokenTypes.ANNOTATION_DEF);
 112  
     }
 113  
 
 114  
     /**
 115  
      * Returns whether a node is directly contained within a specified block.
 116  
      *
 117  
      * @param node the node to check if directly contained within a specified block.
 118  
      * @param tokenType type of token.
 119  
      * @return a {@code boolean} value
 120  
      */
 121  
     private static boolean isInBlockOf(DetailAST node, int tokenType) {
 122  8563
         boolean returnValue = false;
 123  
 
 124  
         // Loop up looking for a containing interface block
 125  8563
         for (DetailAST token = node.getParent();
 126  21083
              token != null && !returnValue;
 127  12520
              token = token.getParent()) {
 128  20745
             final int type = token.getType();
 129  20745
             if (type == tokenType) {
 130  148
                 returnValue = true;
 131  
             }
 132  20597
             else if (type == TokenTypes.CLASS_DEF
 133  
                 || type == TokenTypes.ENUM_DEF
 134  
                 || type == TokenTypes.INTERFACE_DEF
 135  
                 || type == TokenTypes.ANNOTATION_DEF
 136  
                 || type == TokenTypes.LITERAL_NEW) {
 137  103
                 break;
 138  
             }
 139  
 
 140  
         }
 141  
 
 142  8563
         return returnValue;
 143  
     }
 144  
 
 145  
     /**
 146  
      * Returns whether a node is directly contained within an interface or
 147  
      * annotation block.
 148  
      *
 149  
      * @param node the node to check if directly contained within an interface
 150  
      *     or annotation block.
 151  
      * @return a {@code boolean} value
 152  
      */
 153  
     public static boolean isInInterfaceOrAnnotationBlock(DetailAST node) {
 154  4047
         return isInInterfaceBlock(node) || isInAnnotationBlock(node);
 155  
     }
 156  
 
 157  
     /**
 158  
      * Returns whether a node is directly contained within an enum block.
 159  
      *
 160  
      * @param node the node to check if directly contained within an enum block.
 161  
      * @return a {@code boolean} value
 162  
      */
 163  
     public static boolean isInEnumBlock(DetailAST node) {
 164  25
         boolean returnValue = false;
 165  
 
 166  
         // Loop up looking for a containing interface block
 167  25
         for (DetailAST token = node.getParent();
 168  45
              token != null && !returnValue;
 169  20
              token = token.getParent()) {
 170  41
             final int type = token.getType();
 171  41
             if (type == TokenTypes.ENUM_DEF) {
 172  2
                 returnValue = true;
 173  
             }
 174  39
             else if (type == TokenTypes.INTERFACE_DEF
 175  
                 || type == TokenTypes.ANNOTATION_DEF
 176  
                 || type == TokenTypes.CLASS_DEF
 177  
                 || type == TokenTypes.LITERAL_NEW) {
 178  2
                 break;
 179  
             }
 180  
         }
 181  
 
 182  25
         return returnValue;
 183  
     }
 184  
 
 185  
     /**
 186  
      * Returns whether the scope of a node is restricted to a code block.
 187  
      * A code block is a method or constructor body, an initializer block, or lambda body.
 188  
      *
 189  
      * @param node the node to check
 190  
      * @return a {@code boolean} value
 191  
      */
 192  
     public static boolean isInCodeBlock(DetailAST node) {
 193  975
         boolean returnValue = false;
 194  
 
 195  
         // Loop up looking for a containing code block
 196  975
         for (DetailAST token = node.getParent();
 197  3739
              token != null;
 198  2764
              token = token.getParent()) {
 199  2848
             final int type = token.getType();
 200  2848
             if (type == TokenTypes.METHOD_DEF
 201  
                     || type == TokenTypes.CTOR_DEF
 202  
                     || type == TokenTypes.INSTANCE_INIT
 203  
                     || type == TokenTypes.STATIC_INIT
 204  
                     || type == TokenTypes.LAMBDA) {
 205  84
                 returnValue = true;
 206  84
                 break;
 207  
             }
 208  
         }
 209  
 
 210  975
         return returnValue;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Returns whether a node is contained in the outer most type block.
 215  
      *
 216  
      * @param node the node to check
 217  
      * @return a {@code boolean} value
 218  
      */
 219  
     public static boolean isOuterMostType(DetailAST node) {
 220  80
         boolean returnValue = true;
 221  80
         for (DetailAST parent = node.getParent();
 222  88
              parent != null;
 223  8
              parent = parent.getParent()) {
 224  19
             if (parent.getType() == TokenTypes.CLASS_DEF
 225  11
                 || parent.getType() == TokenTypes.INTERFACE_DEF
 226  10
                 || parent.getType() == TokenTypes.ANNOTATION_DEF
 227  9
                 || parent.getType() == TokenTypes.ENUM_DEF) {
 228  11
                 returnValue = false;
 229  11
                 break;
 230  
             }
 231  
         }
 232  
 
 233  80
         return returnValue;
 234  
     }
 235  
 
 236  
     /**
 237  
      * Determines whether a node is a local variable definition.
 238  
      * I.e. if it is declared in a code block, a for initializer,
 239  
      * or a catch parameter.
 240  
      * @param node the node to check.
 241  
      * @return whether aAST is a local variable definition.
 242  
      */
 243  
     public static boolean isLocalVariableDef(DetailAST node) {
 244  3008
         boolean localVariableDef = false;
 245  
         // variable declaration?
 246  3008
         if (node.getType() == TokenTypes.VARIABLE_DEF) {
 247  2773
             final DetailAST parent = node.getParent();
 248  2773
             final int type = parent.getType();
 249  2773
             localVariableDef = type == TokenTypes.SLIST
 250  
                     || type == TokenTypes.FOR_INIT
 251  
                     || type == TokenTypes.FOR_EACH_CLAUSE;
 252  
         }
 253  
         // catch parameter?
 254  3008
         if (node.getType() == TokenTypes.PARAMETER_DEF) {
 255  151
             final DetailAST parent = node.getParent();
 256  151
             localVariableDef = parent.getType() == TokenTypes.LITERAL_CATCH;
 257  
         }
 258  
 
 259  3008
         if (node.getType() == TokenTypes.RESOURCE) {
 260  10
             localVariableDef = true;
 261  
         }
 262  3008
         return localVariableDef;
 263  
     }
 264  
 
 265  
     /**
 266  
      * Determines whether a node is a class field definition.
 267  
      * I.e. if a variable is not declared in a code block, a for initializer,
 268  
      * or a catch parameter.
 269  
      * @param node the node to check.
 270  
      * @return whether a node is a class field definition.
 271  
      */
 272  
     public static boolean isClassFieldDef(DetailAST node) {
 273  13541
         return node.getType() == TokenTypes.VARIABLE_DEF && !isLocalVariableDef(node);
 274  
     }
 275  
 
 276  
     /**
 277  
      * Checks whether ast node is in a specific scope.
 278  
      * @param ast the node to check.
 279  
      * @param scope a {@code Scope} value.
 280  
      * @return true if the ast node is in the scope.
 281  
      */
 282  
     public static boolean isInScope(DetailAST ast, Scope scope) {
 283  181
         final Scope surroundingScopeOfAstToken = getSurroundingScope(ast);
 284  181
         return surroundingScopeOfAstToken == scope;
 285  
     }
 286  
 }