001///////////////////////////////////////////////////////////////////////////////////////////////
002// checkstyle: Checks Java source code and other text files for adherence to a set of rules.
003// Copyright (C) 2001-2023 the original author or authors.
004//
005// This library is free software; you can redistribute it and/or
006// modify it under the terms of the GNU Lesser General Public
007// License as published by the Free Software Foundation; either
008// version 2.1 of the License, or (at your option) any later version.
009//
010// This library is distributed in the hope that it will be useful,
011// but WITHOUT ANY WARRANTY; without even the implied warranty of
012// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013// Lesser General Public License for more details.
014//
015// You should have received a copy of the GNU Lesser General Public
016// License along with this library; if not, write to the Free Software
017// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
018///////////////////////////////////////////////////////////////////////////////////////////////
019
020package com.puppycrawl.tools.checkstyle.checks.metrics;
021
022import java.math.BigInteger;
023import java.util.ArrayDeque;
024import java.util.Deque;
025import java.util.concurrent.atomic.AtomicInteger;
026
027import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
028import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
029import com.puppycrawl.tools.checkstyle.api.DetailAST;
030import com.puppycrawl.tools.checkstyle.api.TokenTypes;
031import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
032
033/**
034 * <p>
035 * Checks the NPATH complexity against a specified limit.
036 * </p>
037 * <p>
038 * The NPATH metric computes the number of possible execution paths through a
039 * function(method). It takes into account the nesting of conditional statements
040 * and multipart boolean expressions (A &amp;&amp; B, C || D, E ? F :G and
041 * their combinations).
042 * </p>
043 * <p>
044 * The NPATH metric was designed base on Cyclomatic complexity to avoid problem
045 * of Cyclomatic complexity metric like nesting level within a function(method).
046 * </p>
047 * <p>
048 * Metric was described at <a href="http://dl.acm.org/citation.cfm?id=42379">
049 * "NPATH: a measure of execution pathcomplexity and its applications"</a>.
050 * If you need detailed description of algorithm, please read that article,
051 * it is well written and have number of examples and details.
052 * </p>
053 * <p>
054 * Here is some quotes:
055 * </p>
056 * <blockquote>
057 * An NPATH threshold value of 200 has been established for a function.
058 * The value 200 is based on studies done at AT&amp;T Bell Laboratories [1988 year].
059 * </blockquote>
060 * <blockquote>
061 * Some of the most effective methods of reducing the NPATH value include:
062 * <ul>
063 * <li>
064 * distributing functionality;
065 * </li>
066 * <li>
067 * implementing multiple if statements as a switch statement;
068 * </li>
069 * <li>
070 * creating a separate function for logical expressions with a high count of
071 * variables and (&amp;&amp;) and or (||) operators.
072 * </li>
073 * </ul>
074 * </blockquote>
075 * <blockquote>
076 * Although strategies to reduce the NPATH complexity of functions are important,
077 * care must be taken not to distort the logical clarity of the software by
078 * applying a strategy to reduce the complexity of functions. That is, there is
079 * a point of diminishing return beyond which a further attempt at reduction of
080 * complexity distorts the logical clarity of the system structure.
081 * </blockquote>
082 * <table>
083 * <caption>Examples</caption>
084 * <thead><tr><th>Structure</th><th>Complexity expression</th></tr></thead>
085 * <tr><td>if ([expr]) { [if-range] }</td><td>NP(if-range) + 1 + NP(expr)</td></tr>
086 * <tr><td>if ([expr]) { [if-range] } else { [else-range] }</td>
087 * <td>NP(if-range)+ NP(else-range) + NP(expr)</td></tr>
088 * <tr><td>while ([expr]) { [while-range] }</td><td>NP(while-range) + NP(expr) + 1</td></tr>
089 * <tr><td>do { [do-range] } while ([expr])</td><td>NP(do-range) + NP(expr) + 1</td></tr>
090 * <tr><td>for([expr1]; [expr2]; [expr3]) { [for-range] }</td>
091 * <td>NP(for-range) + NP(expr1)+ NP(expr2) + NP(expr3) + 1</td></tr>
092 * <tr><td>switch ([expr]) { case : [case-range] default: [default-range] }</td>
093 * <td>S(i=1:i=n)NP(case-range[i]) + NP(default-range) + NP(expr)</td></tr>
094 * <tr><td>[expr1] ? [expr2] : [expr3]</td><td>NP(expr1) + NP(expr2) + NP(expr3) + 2</td></tr>
095 * <tr><td>goto label</td><td>1</td></tr><tr><td>break</td><td>1</td></tr>
096 * <tr><td>Expressions</td>
097 * <td>Number of &amp;&amp; and || operators in expression. No operators - 0</td></tr>
098 * <tr><td>continue</td><td>1</td></tr><tr><td>return</td><td>1</td></tr>
099 * <tr><td>Statement (even sequential statements)</td><td>1</td></tr>
100 * <tr><td>Empty block {}</td><td>1</td></tr><tr><td>Function call</td><td>1</td>
101 * </tr><tr><td>Function(Method) declaration or Block</td><td>P(i=1:i=N)NP(Statement[i])</td></tr>
102 * </table>
103 * <p>
104 * <b>Rationale:</b> Nejmeh says that his group had an informal NPATH limit of
105 * 200 on individual routines; functions(methods) that exceeded this value were
106 * candidates for further decomposition - or at least a closer look.
107 * <b>Please do not be fanatic with limit 200</b> - choose number that suites
108 * your project style. Limit 200 is empirical number base on some sources of at
109 * AT&amp;T Bell Laboratories of 1988 year.
110 * </p>
111 * <ul>
112 * <li>
113 * Property {@code max} - Specify the maximum threshold allowed.
114 * Type is {@code int}.
115 * Default value is {@code 200}.
116 * </li>
117 * </ul>
118 * <p>
119 * To configure the check:
120 * </p>
121 * <pre>
122 * &lt;module name="NPathComplexity"/&gt;
123 * </pre>
124 * <p>
125 * Example:
126 * </p>
127 * <pre>
128 * public abstract class Test {
129 *
130 * final int a = 0;
131 * int b = 0;
132 *
133 * public void foo() { // OK, NPath complexity is less than default threshold
134 *   // function consists of one if-else block with an NPath Complexity of 3
135 *   if (a &gt; 10) {
136 *     if (a &gt; b) { // nested if-else decision tree adds 2 to the complexity count
137 *       buzz();
138 *     } else {
139 *       fizz();
140 *     }
141 *   } else { // last possible outcome of the main if-else block, adds 1 to complexity
142 *     buzz();
143 *   }
144 * }
145 *
146 * public void boo() { // violation, NPath complexity is 217 (max allowed is 200)
147 *   // looping through 3 switch statements produces 6^3 + 1 (217) possible outcomes
148 *   for(int i = 0; i &lt; b; i++) { // for statement adds 1 to final complexity
149 *     switch(i) { // each independent switch statement multiplies complexity by 6
150 *       case a:
151 *         // ternary with &amp;&amp; adds 3 to switch's complexity
152 *         print(f(i) &amp;&amp; g(i) ? fizz() : buzz());
153 *       default:
154 *         // ternary with || adds 3 to switch's complexity
155 *         print(f(i) || g(i) ? fizz() : buzz());
156 *     }
157 *     switch(i - 1) { // multiplies complexity by 6
158 *       case a:
159 *         print(f(i) &amp;&amp; g(i) ? fizz() : buzz());
160 *       default:
161 *         print(f(i) || g(i) ? fizz() : buzz());
162 *     }
163 *     switch(i + 1) { // multiplies complexity by 6
164 *       case a:
165 *         print(f(i) &amp;&amp; g(i) ? fizz() : buzz());
166 *       default:
167 *         print(f(i) || g(i) ? fizz() : buzz());
168 *     }
169 *   }
170 * }
171 *
172 * public abstract boolean f(int x);
173 * public abstract boolean g(int x);
174 * public abstract String fizz();
175 * public abstract String buzz();
176 * public abstract void print(String str);
177 * }
178 * </pre>
179 * <p>
180 * To configure the check with a threshold of 100:
181 * </p>
182 * <pre>
183 * &lt;module name="NPathComplexity"&gt;
184 *   &lt;property name="max" value="100"/&gt;
185 * &lt;/module&gt;
186 * </pre>
187 * <p>
188 * Example:
189 * </p>
190 * <pre>
191 * public abstract class Test1 {
192 * public void foo() { // violation, NPath complexity is 128 (max allowed is 100)
193 *   int a,b,t,m,n;
194 *   a=b=t=m=n = 0;
195 *
196 *   // Complexity is achieved by choosing from 2 options 7 times (2^7 = 128 possible outcomes)
197 *   if (a &gt; b) { // non-nested if-else decision tree multiplies complexity by 2
198 *     bar();
199 *   } else {
200 *     baz();
201 *   }
202 *
203 *   print(t &gt; 1 ? bar() : baz()); // 5 ternary statements multiply complexity by 2^5
204 *   print(t &gt; 2 ? bar() : baz());
205 *   print(t &gt; 3 ? bar() : baz());
206 *   print(t &gt; 4 ? bar() : baz());
207 *   print(t &gt; 5 ? bar() : baz());
208 *
209 *   if (m &gt; n) { // multiplies complexity by 2
210 *     baz();
211 *   } else {
212 *     bar();
213 *   }
214 * }
215 *
216 * public abstract String bar();
217 * public abstract String baz();
218 * public abstract void print(String str);
219 * }
220 * </pre>
221 * <p>
222 * Parent is {@code com.puppycrawl.tools.checkstyle.TreeWalker}
223 * </p>
224 * <p>
225 * Violation Message Keys:
226 * </p>
227 * <ul>
228 * <li>
229 * {@code npathComplexity}
230 * </li>
231 * </ul>
232 *
233 * @since 3.4
234 */
235// -@cs[AbbreviationAsWordInName] Can't change check name
236@FileStatefulCheck
237public final class NPathComplexityCheck extends AbstractCheck {
238
239    /**
240     * A key is pointing to the warning message text in "messages.properties"
241     * file.
242     */
243    public static final String MSG_KEY = "npathComplexity";
244
245    /** Default allowed complexity. */
246    private static final int DEFAULT_MAX = 200;
247
248    /** The initial current value. */
249    private static final BigInteger INITIAL_VALUE = BigInteger.ZERO;
250
251    /**
252     * Stack of NP values for ranges.
253     */
254    private final Deque<BigInteger> rangeValues = new ArrayDeque<>();
255
256    /** Stack of NP values for expressions. */
257    private final Deque<Integer> expressionValues = new ArrayDeque<>();
258
259    /** Stack of belongs to range values for question operator. */
260    private final Deque<Boolean> afterValues = new ArrayDeque<>();
261
262    /**
263     * Range of the last processed expression. Used for checking that ternary operation
264     * which is a part of expression won't be processed for second time.
265     */
266    private final TokenEnd processingTokenEnd = new TokenEnd();
267
268    /** NP value for current range. */
269    private BigInteger currentRangeValue;
270
271    /** Specify the maximum threshold allowed. */
272    private int max = DEFAULT_MAX;
273
274    /** True, when branch is visited, but not leaved. */
275    private boolean branchVisited;
276
277    /**
278     * Setter to specify the maximum threshold allowed.
279     *
280     * @param max the maximum threshold
281     */
282    public void setMax(int max) {
283        this.max = max;
284    }
285
286    @Override
287    public int[] getDefaultTokens() {
288        return getRequiredTokens();
289    }
290
291    @Override
292    public int[] getAcceptableTokens() {
293        return getRequiredTokens();
294    }
295
296    @Override
297    public int[] getRequiredTokens() {
298        return new int[] {
299            TokenTypes.CTOR_DEF,
300            TokenTypes.METHOD_DEF,
301            TokenTypes.STATIC_INIT,
302            TokenTypes.INSTANCE_INIT,
303            TokenTypes.LITERAL_WHILE,
304            TokenTypes.LITERAL_DO,
305            TokenTypes.LITERAL_FOR,
306            TokenTypes.LITERAL_IF,
307            TokenTypes.LITERAL_ELSE,
308            TokenTypes.LITERAL_SWITCH,
309            TokenTypes.CASE_GROUP,
310            TokenTypes.LITERAL_TRY,
311            TokenTypes.LITERAL_CATCH,
312            TokenTypes.QUESTION,
313            TokenTypes.LITERAL_RETURN,
314            TokenTypes.LITERAL_DEFAULT,
315            TokenTypes.COMPACT_CTOR_DEF,
316            TokenTypes.SWITCH_RULE,
317        };
318    }
319
320    @Override
321    public void beginTree(DetailAST rootAST) {
322        rangeValues.clear();
323        expressionValues.clear();
324        afterValues.clear();
325        processingTokenEnd.reset();
326        currentRangeValue = INITIAL_VALUE;
327        branchVisited = false;
328    }
329
330    @Override
331    public void visitToken(DetailAST ast) {
332        switch (ast.getType()) {
333            case TokenTypes.LITERAL_IF:
334            case TokenTypes.LITERAL_SWITCH:
335            case TokenTypes.LITERAL_WHILE:
336            case TokenTypes.LITERAL_DO:
337            case TokenTypes.LITERAL_FOR:
338                visitConditional(ast, 1);
339                break;
340            case TokenTypes.QUESTION:
341                visitUnitaryOperator(ast, 2);
342                break;
343            case TokenTypes.LITERAL_RETURN:
344                visitUnitaryOperator(ast, 0);
345                break;
346            case TokenTypes.CASE_GROUP:
347                final int caseNumber = countCaseTokens(ast);
348                branchVisited = true;
349                pushValue(caseNumber);
350                break;
351            case TokenTypes.SWITCH_RULE:
352                final int caseConstantNumber = countCaseConstants(ast);
353                branchVisited = true;
354                pushValue(caseConstantNumber);
355                break;
356            case TokenTypes.LITERAL_ELSE:
357                branchVisited = true;
358                if (currentRangeValue.equals(BigInteger.ZERO)) {
359                    currentRangeValue = BigInteger.ONE;
360                }
361                pushValue(0);
362                break;
363            case TokenTypes.LITERAL_TRY:
364            case TokenTypes.LITERAL_CATCH:
365            case TokenTypes.LITERAL_DEFAULT:
366                pushValue(1);
367                break;
368            case TokenTypes.CTOR_DEF:
369            case TokenTypes.METHOD_DEF:
370            case TokenTypes.INSTANCE_INIT:
371            case TokenTypes.STATIC_INIT:
372            case TokenTypes.COMPACT_CTOR_DEF:
373                pushValue(0);
374                break;
375            default:
376                break;
377        }
378    }
379
380    @Override
381    public void leaveToken(DetailAST ast) {
382        switch (ast.getType()) {
383            case TokenTypes.LITERAL_WHILE:
384            case TokenTypes.LITERAL_DO:
385            case TokenTypes.LITERAL_FOR:
386            case TokenTypes.LITERAL_IF:
387            case TokenTypes.LITERAL_SWITCH:
388                leaveConditional();
389                break;
390            case TokenTypes.LITERAL_TRY:
391                leaveMultiplyingConditional();
392                break;
393            case TokenTypes.LITERAL_RETURN:
394            case TokenTypes.QUESTION:
395                leaveUnitaryOperator();
396                break;
397            case TokenTypes.LITERAL_CATCH:
398                leaveAddingConditional();
399                break;
400            case TokenTypes.LITERAL_DEFAULT:
401                leaveBranch();
402                break;
403            case TokenTypes.LITERAL_ELSE:
404            case TokenTypes.CASE_GROUP:
405            case TokenTypes.SWITCH_RULE:
406                leaveBranch();
407                branchVisited = false;
408                break;
409            case TokenTypes.CTOR_DEF:
410            case TokenTypes.METHOD_DEF:
411            case TokenTypes.INSTANCE_INIT:
412            case TokenTypes.STATIC_INIT:
413            case TokenTypes.COMPACT_CTOR_DEF:
414                leaveMethodDef(ast);
415                break;
416            default:
417                break;
418        }
419    }
420
421    /**
422     * Visits if, while, do-while, for and switch tokens - all of them have expression in
423     * parentheses which is used for calculation.
424     *
425     * @param ast visited token.
426     * @param basicBranchingFactor default number of branches added.
427     */
428    private void visitConditional(DetailAST ast, int basicBranchingFactor) {
429        int expressionValue = basicBranchingFactor;
430        DetailAST bracketed;
431        for (bracketed = ast.findFirstToken(TokenTypes.LPAREN);
432                bracketed.getType() != TokenTypes.RPAREN;
433                bracketed = bracketed.getNextSibling()) {
434            expressionValue += countConditionalOperators(bracketed);
435        }
436        processingTokenEnd.setToken(bracketed);
437        pushValue(expressionValue);
438    }
439
440    /**
441     * Visits ternary operator (?:) and return tokens. They differ from those processed by
442     * visitConditional method in that their expression isn't bracketed.
443     *
444     * @param ast visited token.
445     * @param basicBranchingFactor number of branches inherently added by this token.
446     */
447    private void visitUnitaryOperator(DetailAST ast, int basicBranchingFactor) {
448        final boolean isAfter = processingTokenEnd.isAfter(ast);
449        afterValues.push(isAfter);
450        if (!isAfter) {
451            processingTokenEnd.setToken(getLastToken(ast));
452            final int expressionValue = basicBranchingFactor + countConditionalOperators(ast);
453            pushValue(expressionValue);
454        }
455    }
456
457    /**
458     * Leaves ternary operator (?:) and return tokens.
459     */
460    private void leaveUnitaryOperator() {
461        if (Boolean.FALSE.equals(afterValues.pop())) {
462            final Values valuePair = popValue();
463            BigInteger basicRangeValue = valuePair.getRangeValue();
464            BigInteger expressionValue = valuePair.getExpressionValue();
465            if (expressionValue.equals(BigInteger.ZERO)) {
466                expressionValue = BigInteger.ONE;
467            }
468            if (basicRangeValue.equals(BigInteger.ZERO)) {
469                basicRangeValue = BigInteger.ONE;
470            }
471            currentRangeValue = currentRangeValue.add(expressionValue).multiply(basicRangeValue);
472        }
473    }
474
475    /** Leaves while, do, for, if, ternary (?::), return or switch. */
476    private void leaveConditional() {
477        final Values valuePair = popValue();
478        final BigInteger expressionValue = valuePair.getExpressionValue();
479        BigInteger basicRangeValue = valuePair.getRangeValue();
480        if (currentRangeValue.equals(BigInteger.ZERO)) {
481            currentRangeValue = BigInteger.ONE;
482        }
483        if (basicRangeValue.equals(BigInteger.ZERO)) {
484            basicRangeValue = BigInteger.ONE;
485        }
486        currentRangeValue = currentRangeValue.add(expressionValue).multiply(basicRangeValue);
487    }
488
489    /** Leaves else, default or case group tokens. */
490    private void leaveBranch() {
491        final Values valuePair = popValue();
492        final BigInteger basicRangeValue = valuePair.getRangeValue();
493        final BigInteger expressionValue = valuePair.getExpressionValue();
494        if (branchVisited && currentRangeValue.equals(BigInteger.ZERO)) {
495            currentRangeValue = BigInteger.ONE;
496        }
497        currentRangeValue = currentRangeValue.subtract(BigInteger.ONE)
498                .add(basicRangeValue)
499                .add(expressionValue);
500    }
501
502    /**
503     * Process the end of a method definition.
504     *
505     * @param ast the token type representing the method definition
506     */
507    private void leaveMethodDef(DetailAST ast) {
508        final BigInteger bigIntegerMax = BigInteger.valueOf(max);
509        if (currentRangeValue.compareTo(bigIntegerMax) > 0) {
510            log(ast, MSG_KEY, currentRangeValue, bigIntegerMax);
511        }
512        popValue();
513        currentRangeValue = INITIAL_VALUE;
514    }
515
516    /** Leaves catch. */
517    private void leaveAddingConditional() {
518        currentRangeValue = currentRangeValue.add(popValue().getRangeValue().add(BigInteger.ONE));
519    }
520
521    /**
522     * Pushes the current range value on the range value stack. Pushes this token expression value
523     * on the expression value stack.
524     *
525     * @param expressionValue value of expression calculated for current token.
526     */
527    private void pushValue(Integer expressionValue) {
528        rangeValues.push(currentRangeValue);
529        expressionValues.push(expressionValue);
530        currentRangeValue = INITIAL_VALUE;
531    }
532
533    /**
534     * Pops values from both stack of expression values and stack of range values.
535     *
536     * @return pair of head values from both of the stacks.
537     */
538    private Values popValue() {
539        final int expressionValue = expressionValues.pop();
540        return new Values(rangeValues.pop(), BigInteger.valueOf(expressionValue));
541    }
542
543    /** Leaves try. */
544    private void leaveMultiplyingConditional() {
545        currentRangeValue = currentRangeValue.add(BigInteger.ONE)
546                .multiply(popValue().getRangeValue().add(BigInteger.ONE));
547    }
548
549    /**
550     * Calculates number of conditional operators, including inline ternary operator, for a token.
551     *
552     * @param ast inspected token.
553     * @return number of conditional operators.
554     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.23">
555     * Java Language Specification, &sect;15.23</a>
556     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.24">
557     * Java Language Specification, &sect;15.24</a>
558     * @see <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25">
559     * Java Language Specification, &sect;15.25</a>
560     */
561    private static int countConditionalOperators(DetailAST ast) {
562        int number = 0;
563        for (DetailAST child = ast.getFirstChild(); child != null;
564                child = child.getNextSibling()) {
565            final int type = child.getType();
566            if (type == TokenTypes.LOR || type == TokenTypes.LAND) {
567                number++;
568            }
569            else if (type == TokenTypes.QUESTION) {
570                number += 2;
571            }
572            number += countConditionalOperators(child);
573        }
574        return number;
575    }
576
577    /**
578     * Finds a leaf, which is the most distant from the root.
579     *
580     * @param ast the root of tree.
581     * @return the leaf.
582     */
583    private static DetailAST getLastToken(DetailAST ast) {
584        final DetailAST lastChild = ast.getLastChild();
585        final DetailAST result;
586        if (lastChild.getFirstChild() == null) {
587            result = lastChild;
588        }
589        else {
590            result = getLastToken(lastChild);
591        }
592        return result;
593    }
594
595    /**
596     * Counts number of case tokens subject to a case group token.
597     *
598     * @param ast case group token.
599     * @return number of case tokens.
600     */
601    private static int countCaseTokens(DetailAST ast) {
602        int counter = 0;
603        for (DetailAST iterator = ast.getFirstChild(); iterator != null;
604                iterator = iterator.getNextSibling()) {
605            if (iterator.getType() == TokenTypes.LITERAL_CASE) {
606                counter++;
607            }
608        }
609        return counter;
610    }
611
612    /**
613     * Counts number of case constants (EXPR) tokens in a switch labeled rule.
614     *
615     * @param ast switch rule token.
616     * @return number of case constant (EXPR) tokens.
617     */
618    private static int countCaseConstants(DetailAST ast) {
619        final AtomicInteger counter = new AtomicInteger();
620        final DetailAST literalCase = ast.getFirstChild();
621
622        TokenUtil.forEachChild(literalCase,
623            TokenTypes.EXPR, node -> counter.getAndIncrement());
624
625        return counter.get();
626    }
627
628    /**
629     * Coordinates of token end. Used to prevent inline ternary
630     * operator from being processed twice.
631     */
632    private static final class TokenEnd {
633
634        /** End line of token. */
635        private int endLineNo;
636
637        /** End column of token. */
638        private int endColumnNo;
639
640        /**
641         * Sets end coordinates from given token.
642         *
643         * @param endToken token.
644         */
645        public void setToken(DetailAST endToken) {
646            if (!isAfter(endToken)) {
647                endLineNo = endToken.getLineNo();
648                endColumnNo = endToken.getColumnNo();
649            }
650        }
651
652        /** Sets end token coordinates to the start of the file. */
653        public void reset() {
654            endLineNo = 0;
655            endColumnNo = 0;
656        }
657
658        /**
659         * Checks if saved coordinates located after given token.
660         *
661         * @param ast given token.
662         * @return true, if saved coordinates located after given token.
663         */
664        public boolean isAfter(DetailAST ast) {
665            final int lineNo = ast.getLineNo();
666            final int columnNo = ast.getColumnNo();
667            return lineNo <= endLineNo
668                && (lineNo != endLineNo
669                || columnNo <= endColumnNo);
670        }
671
672    }
673
674    /**
675     * Class that store range value and expression value.
676     */
677    private static final class Values {
678
679        /** NP value for range. */
680        private final BigInteger rangeValue;
681
682        /** NP value for expression. */
683        private final BigInteger expressionValue;
684
685        /**
686         * Constructor that assigns all of class fields.
687         *
688         * @param valueOfRange NP value for range
689         * @param valueOfExpression NP value for expression
690         */
691        private Values(BigInteger valueOfRange, BigInteger valueOfExpression) {
692            rangeValue = valueOfRange;
693            expressionValue = valueOfExpression;
694        }
695
696        /**
697         * Returns NP value for range.
698         *
699         * @return NP value for range
700         */
701        public BigInteger getRangeValue() {
702            return rangeValue;
703        }
704
705        /**
706         * Returns NP value for expression.
707         *
708         * @return NP value for expression
709         */
710        public BigInteger getExpressionValue() {
711            return expressionValue;
712        }
713
714    }
715
716}