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

eu.cqse.check.framework.util.SwitchStatementUtils Maven / Gradle / Ivy

Go to download

The Teamscale Custom Check API allows users to extend Teamscale by writing custom analyses that create findings.

There is a newer version: 2024.7.2
Show newest version
/*
 * Copyright (c) CQSE GmbH
 *
 * 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 eu.cqse.check.framework.util;

import static eu.cqse.check.framework.scanner.ETokenType.ATTRIBUTE;
import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER;
import static eu.cqse.check.framework.scanner.ETokenType.LPAREN;
import static eu.cqse.check.framework.scanner.ETokenType.RPAREN;
import static eu.cqse.check.framework.shallowparser.SubTypeNames.ANONYMOUS_BLOCK;
import static eu.cqse.check.framework.shallowparser.SubTypeNames.CASE;
import static eu.cqse.check.framework.shallowparser.SubTypeNames.DEFAULT;
import static eu.cqse.check.framework.shallowparser.SubTypeNames.SWITCH;
import static eu.cqse.check.framework.shallowparser.SubTypeNames.SWITCH_EXPRESSION;
import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.META;
import static eu.cqse.check.framework.shallowparser.framework.EShallowEntityType.STATEMENT;

import java.util.List;
import java.util.Set;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.conqat.lib.commons.collections.CollectionUtils;

import eu.cqse.check.framework.core.CheckException;
import eu.cqse.check.framework.core.ICheckContext;
import eu.cqse.check.framework.core.phase.ECodeViewOption;
import eu.cqse.check.framework.scanner.IToken;
import eu.cqse.check.framework.shallowparser.SubTypeNames;
import eu.cqse.check.framework.shallowparser.TokenStreamUtils;
import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType;
import eu.cqse.check.framework.shallowparser.framework.ShallowEntity;

/**
 * Provides utility methods for handling switch, case and label statements
 */
public class SwitchStatementUtils {

	private static final Logger LOGGER = LogManager.getLogger();

	/**
	 * A set of C++ attributes which may be used to indicate that a fallthrough in a switch statement is
	 * intended.
	 */
	private static final Set FALLTHROUGH_ATTRIBUTES = CollectionUtils.asHashSet("fallthrough",
			"clang::fallthrough");

	/** Returns whether given statement is a switch or not. */
	public static boolean isSwitch(ShallowEntity entity) {
		return entity.getType() == STATEMENT
				&& (entity.getSubtype().equals(SWITCH) || entity.getSubtype().equals(SWITCH_EXPRESSION));
	}

	/** Returns whether given statement is a case or not. */
	public static boolean isCase(ShallowEntity entity) {
		return entity.getType() == META && entity.getSubtype().equals(CASE);
	}

	/** Returns whether given statement is a default or not. */
	public static boolean isDefault(ShallowEntity entity) {
		return entity.getType() == META && entity.getSubtype().equals(DEFAULT);
	}

	/** Returns whether given statement is an anonymous block. */
	public static boolean isAnonymousBlock(ShallowEntity entity) {
		return entity.getType() == STATEMENT && entity.getSubtype().equals(ANONYMOUS_BLOCK);
	}

	/** Returns true if statement entity is a META one and its a case or default. */
	public static boolean isCaseOrDefault(ShallowEntity entity) {
		return entity.getType() == META && (entity.getSubtype().equals(CASE) || entity.getSubtype().equals(DEFAULT));
	}

	/**
	 * Returns whether the given {@link ShallowEntity entity} represents a fallthrough attribute
	 *
	 * @param context
	 *            the check context
	 * @param caseEntity
	 *            the entity of the case in which the entity to check is located
	 * @param entityToCheck
	 *            the entity for which it should be determined if it represents a fallthrough attribute
	 */
	public static boolean isFallThroughAttribute(ICheckContext context, ShallowEntity caseEntity,
			ShallowEntity entityToCheck) {
		if (caseEntity == null || entityToCheck == null) {
			return false;
		}

		return isCppFallthroughAttribute(entityToCheck)
				|| isGNUFallthroughAttribute(context, caseEntity, entityToCheck);
	}

	/**
	 * Returns whether the given entity represent a C++ fallthrough attribute.
	 *
	 * @see #FALLTHROUGH_ATTRIBUTES
	 */
	private static boolean isCppFallthroughAttribute(ShallowEntity entity) {
		return entity.getType() == EShallowEntityType.META
				&& SubTypeNames.ATTRIBUTE_ANNOTATION.equals(entity.getSubtype())
				&& FALLTHROUGH_ATTRIBUTES.contains(entity.getName());
	}

	/**
	 * Returns whether the given {@link ShallowEntity entity} represents a GNU fallthrough-attribute.
	 * 

* During pre-processing __attribute__((fallthrough)); is being reduced to an empty * statement and only a semicolon remains. If the attribute is written without a semicolon this code * will not work, however it will also produce a compiler warning on their side. */ private static boolean isGNUFallthroughAttribute(ICheckContext context, ShallowEntity caseEntity, ShallowEntity entityToCheck) { if (!entityToCheck.getSubtype().equals(SubTypeNames.EMPTY_STATEMENT)) { return false; } List unprocessedTokens = null; try { unprocessedTokens = context.getTokens(ECodeViewOption.FILTERED_PREPROCESSED); } catch (CheckException e) { LOGGER.error("An exception occurred while determining if the entity represent a fallthrough attribute.", e); } // __attribute__ tokens are filtered out during the parsing, therefore the // non-parsed tokens must be more if it is there if (unprocessedTokens == null || unprocessedTokens.size() <= caseEntity.getAllTokensOfFile().size()) { return false; } List preprocessedCaseTokens = TokenStreamUtils.getTokensBetween(unprocessedTokens, caseEntity.getStartOffset(), entityToCheck.getEndOffset()); return hasGNUFallthroughAttribute(preprocessedCaseTokens); } /** Returns whether the given tokens contain a GNU fallthrough attribute. */ private static boolean hasGNUFallthroughAttribute(List tokens) { List indices = TokenStreamUtils.firstTokenOfTypeSequences(tokens, 0, ATTRIBUTE, LPAREN, LPAREN, IDENTIFIER, RPAREN, RPAREN); if (indices.isEmpty()) { return false; } int index = CollectionUtils.getLast(indices); return tokens.get(index + 3).getText().equals("fallthrough"); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy