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

com.xenoamess.p3c.pmd.lang.java.rule.flowcontrol.SwitchStatementRule Maven / Gradle / Ivy

There is a newer version: 2.2.1.0x
Show newest version
/*
 * Copyright 1999-2017 Alibaba Group.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xenoamess.p3c.pmd.lang.java.rule.flowcontrol;

import com.xenoamess.p3c.pmd.lang.java.rule.AbstractAliRule;
import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement;

/**
 * [Mandatory] In a switch block, each case should be finished by break/return.
 * If not, a note should be included to describe at which case it will stop. Within every switch block,
 * a default statement must be present, even if it is empty.
 *
 * @author zenghou.fw
 * @date 2016/11/17
 */
public class SwitchStatementRule extends AbstractAliRule {
    private static final String MESSAGE_KEY_PREFIX = "java.flowcontrol.SwitchStatementRule.violation";

    @Override
    public Object visit(ASTSwitchStatement node, Object data) {
        checkDefault(node, data);

        checkFallThrough(node, data);

        return super.visit(node, data);
    }

    /**
     * Check if switch statement contains default branch
     *
     * @param node node
     * @param data ruleContext
     */
    private void checkDefault(ASTSwitchStatement node, Object data) {
        final String switchLabelCheckXpath = "SwitchLabel[@Default = 'true']";
        final String switchLabeledExpressionCheckXpath = "SwitchLabeledExpression[SwitchLabel[@Default = 'true']]";
        final String switchLabeledBlockCheckXpath = "SwitchLabeledBlock[SwitchLabel[@Default = 'true']]";
        if (
                !node.hasDescendantMatchingXPath(switchLabelCheckXpath)
                        && !node.hasDescendantMatchingXPath(switchLabeledExpressionCheckXpath)
                        && !node.hasDescendantMatchingXPath(switchLabeledBlockCheckXpath)
        ) {
            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + ".nodefault");
        }
    }

    /**
     * Check the availability of break, return, throw, continue in case statement
     *
     * @param node node
     * @param data ruleContext
     */
    private void checkFallThrough(ASTSwitchStatement node, Object data) {
        // refer the rule MissingBreakInSwitch of PMD
        final String xpath = "../SwitchStatement[(count(.//BreakStatement)"
                + " + count(BlockStatement//Statement/ReturnStatement)"
                + " + count(BlockStatement//Statement/ContinueStatement)"
                + " + count(BlockStatement//Statement/ThrowStatement)"
                + " + count(BlockStatement//Statement/IfStatement[@Else='true'"
                + " and Statement[2][ReturnStatement|ContinueStatement|ThrowStatement]]"
                + "/Statement[1][ReturnStatement|ContinueStatement|ThrowStatement])"
                + " + count(SwitchLabel[name(following-sibling::node()) = 'SwitchLabel'])"
                + " + count(SwitchLabel[count(following-sibling::node()) = 0])"
                + "  < count (SwitchLabel[@Default != 'true'])"
                + " + count(SwitchLabel[@Default = 'true']/following-sibling::BlockStatement//Statement" +
                "/ReturnStatement)"
                + " + count(SwitchLabel[@Default = 'true']/following-sibling::BlockStatement//Statement" +
                "/ContinueStatement)"
                + " + count(SwitchLabel[@Default = 'true']/following-sibling::BlockStatement//Statement/ThrowStatement)"
                + ")]";

        if (node.hasDescendantMatchingXPath(xpath)) {
            addViolationWithMessage(data, node, MESSAGE_KEY_PREFIX + ".notermination");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy