001/*-------------------------------------------------------------------------+ 002| | 003| Copyright (c) 2009-2018 CQSE GmbH | 004| | 005+-------------------------------------------------------------------------*/ 006package eu.cqse.check.framework.util.clike; 007 008import java.util.EnumSet; 009import java.util.List; 010import java.util.stream.Collectors; 011 012import org.conqat.lib.commons.collections.CollectionUtils; 013 014import eu.cqse.check.framework.scanner.ETokenType; 015import eu.cqse.check.framework.scanner.IToken; 016import eu.cqse.check.framework.shallowparser.SubTypeNames; 017import eu.cqse.check.framework.shallowparser.framework.ShallowEntity; 018 019/** 020 * This utility class provides methods that are used when working with blocks. 021 */ 022public class ConditionalBlockUtils { 023 /** The blocks that have a condition. */ 024 public static final EnumSet<EConditionalType> BLOCKS_WITH_CONDITION = EnumSet.of(EConditionalType.IF, 025 EConditionalType.ELSE_IF, EConditionalType.CASE); 026 027 /** The blocks that do not have a condition. */ 028 public static final EnumSet<EConditionalType> BLOCKS_WITHOUT_CONDITION = EnumSet.of(EConditionalType.SWITCH, 029 EConditionalType.ELSE, EConditionalType.DEFAULT); 030 031 /** The blocks that correspond to an if block. */ 032 public static final EnumSet<EConditionalType> BLOCKS_CORRESPONDING_TO_IF = EnumSet.of(EConditionalType.ELSE_IF, 033 EConditionalType.ELSE); 034 035 /** The blocks that correspond to a switch block. */ 036 public static final EnumSet<EConditionalType> BLOCKS_CORRESPONDING_TO_SWITCH = EnumSet.of(EConditionalType.CASE, 037 EConditionalType.DEFAULT); 038 039 /** The token types that get sorted out when extracting the condition */ 040 public static final EnumSet<ETokenType> UNWANTED_TOKEN_TYPES_IN_CONDITION = EnumSet.of(ETokenType.SWITCH, 041 ETokenType.LBRACE, ETokenType.IF, ETokenType.ELSEIF, ETokenType.CASE, ETokenType.DOUBLE_DOT, 042 ETokenType.COLON); 043 044 /** 045 * Extracts the {@link EConditionalType} from the given {@link ShallowEntity}. 046 */ 047 public static EConditionalType getBlockTypeFromEntity(ShallowEntity entity) throws IllegalArgumentException { 048 return getBlockTypeFromEntitySubtype(entity.getSubtype()); 049 } 050 051 /** 052 * Converts the Subtype of an entity represented by a string to the 053 * corresponding {@link EConditionalType}. 054 */ 055 public static EConditionalType getBlockTypeFromEntitySubtype(String subtype) throws IllegalArgumentException { 056 /** 057 * The fall-through in this switch construct is intended to clarify which 058 * {@link #SubTypeNames} corresponds to which {@link #EConditionalType}. 059 */ 060 switch (subtype) { 061 case SubTypeNames.IF: 062 case SubTypeNames.IF_LET: 063 case SubTypeNames.IF_VAR: 064 return EConditionalType.IF; 065 case SubTypeNames.ELIF: 066 case SubTypeNames.ELSIF: 067 case SubTypeNames.ELSE_IF: 068 case SubTypeNames.ELSE_IF_NOSPACE: 069 return EConditionalType.ELSE_IF; 070 case SubTypeNames.ELSE: 071 return EConditionalType.ELSE; 072 case SubTypeNames.SWITCH: 073 return EConditionalType.SWITCH; 074 case SubTypeNames.CASE: 075 return EConditionalType.CASE; 076 case SubTypeNames.DEFAULT: 077 return EConditionalType.DEFAULT; 078 default: 079 return null; 080 } 081 } 082 083 /** 084 * Extracts the tokens describing the condition out of the given list of tokens. 085 */ 086 public static List<IToken> extractCondition(ShallowEntity entity) { 087 List<IToken> tokens = getHeaderTokens(entity); 088 return CollectionUtils.filter(tokens, token -> !UNWANTED_TOKEN_TYPES_IN_CONDITION.contains(token.getType()) 089 && token.getLineNumber() == tokens.get(0).getLineNumber()); 090 } 091 092 /** Extracts the header tokens from the entity. */ 093 private static List<IToken> getHeaderTokens(ShallowEntity entity) { 094 int startTokenIndex = entity.getStartOffset(); 095 int endTokenIndex; 096 if (entity.getChildren().size() == 0) { 097 List<IToken> includedTokens = entity.includedTokens(); 098 endTokenIndex = includedTokens.get(includedTokens.size() - 1).getOffset(); 099 } else { 100 endTokenIndex = entity.getChildren().get(0).getStartOffset(); 101 } 102 return entity.includedTokens().stream() 103 .filter(token -> token.getOffset() > startTokenIndex && token.getEndOffset() < endTokenIndex) 104 .collect(Collectors.toList()); 105 } 106}