001package eu.cqse.check.framework.util;
002
003import static eu.cqse.check.framework.scanner.ETokenType.AUTO;
004import static eu.cqse.check.framework.scanner.ETokenType.BOOL;
005import static eu.cqse.check.framework.scanner.ETokenType.CHAR;
006import static eu.cqse.check.framework.scanner.ETokenType.DOT;
007import static eu.cqse.check.framework.scanner.ETokenType.DOUBLE;
008import static eu.cqse.check.framework.scanner.ETokenType.FLOAT;
009import static eu.cqse.check.framework.scanner.ETokenType.ID;
010import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER;
011import static eu.cqse.check.framework.scanner.ETokenType.INT;
012import static eu.cqse.check.framework.scanner.ETokenType.LONG;
013import static eu.cqse.check.framework.scanner.ETokenType.SCOPE;
014import static eu.cqse.check.framework.scanner.ETokenType.SHORT;
015import static eu.cqse.check.framework.scanner.ETokenType.SIGNED;
016import static eu.cqse.check.framework.scanner.ETokenType.UNSIGNED;
017import static eu.cqse.check.framework.scanner.ETokenType.VOID;
018
019import java.util.EnumSet;
020import java.util.List;
021import java.util.Set;
022import java.util.stream.Collectors;
023
024import org.conqat.lib.commons.collections.CollectionUtils;
025
026import eu.cqse.check.framework.scanner.ELanguage;
027import eu.cqse.check.framework.scanner.ETokenType;
028import eu.cqse.check.framework.scanner.IToken;
029import eu.cqse.check.framework.shallowparser.SubTypeNames;
030import eu.cqse.check.framework.shallowparser.TokenStreamTextUtils;
031import eu.cqse.check.framework.shallowparser.TokenStreamUtils;
032import eu.cqse.check.framework.shallowparser.framework.EShallowEntityType;
033import eu.cqse.check.framework.shallowparser.framework.ShallowEntity;
034import eu.cqse.check.framework.util.variable.CLikeVariableUseExtractor;
035
036/** Language feature parser for Objective-C. */
037public class ObjcLanguageFeatureParser extends CLikeLanguageFeatureParserBase {
038
039        /** All token types that can be used to specify a type. */
040        private static final EnumSet<ETokenType> ADDITIONAL_TYPE_TOKENS = EnumSet.of(IDENTIFIER, ID, AUTO);
041
042        /** All token types that can be used to specify a type. */
043        private static final EnumSet<ETokenType> PRIMITIVE_TYPE_TOKENS = EnumSet.of(SIGNED, UNSIGNED, BOOL, CHAR, SHORT,
044                        INT, LONG, FLOAT, DOUBLE, VOID);
045
046        /** All token types that can be used as identifier. */
047        private static final EnumSet<ETokenType> VALID_IDENTIFIERS = EnumSet.of(IDENTIFIER, ETokenType.OPERATOR);
048
049        /** Names of classes that count as generic exceptions. */
050        private static final Set<String> GENERIC_EXCEPTION_NAMES = CollectionUtils.asHashSet("NSException", "id");
051
052        ObjcLanguageFeatureParser() {
053                super(ELanguage.OBJECTIVE_C, VALID_IDENTIFIERS, PRIMITIVE_TYPE_TOKENS, ADDITIONAL_TYPE_TOKENS, SCOPE, ".",
054                                new CLikeVariableUseExtractor(EnumSet.of(DOT), VALID_IDENTIFIERS));
055                super.variableSplitType = ETokenType.COLON;
056        }
057
058        @Override
059        public boolean isImport(ShallowEntity entity) {
060                return entity.getType() == EShallowEntityType.META && entity.getSubtype().equals(SubTypeNames.AT_IMPORT);
061        }
062
063        @Override
064        public String getImportName(ShallowEntity entity) {
065                return TokenStreamTextUtils.concatTokenTexts(
066                                TokenStreamUtils.tokensBetween(entity.ownStartTokens(), ETokenType.IMPORT, ETokenType.SEMICOLON));
067        }
068
069        /**
070         * Determines whether the given class name represents a generic exception.
071         */
072        public boolean isGenericExceptionClass(String className) {
073                return GENERIC_EXCEPTION_NAMES.contains(className);
074        }
075
076        /**
077         * Returns a list of parameter tokens for the given tokensAfterMethodName.
078         * Example for <code>
079         *  -(void)foo1:(int) x1:(int) x2 </code>. Returns
080         * <code>[int, x1, :, int, x2]</code>.
081         */
082
083        @Override
084        public List<IToken> extractParameterTokens(List<IToken> methodStartTokens) {
085
086                // Creating a Sublist of tokensAfterMethodName between COLON ":" and LBRACE"{".
087                List<IToken> tokensAfterMethodName = TokenStreamUtils.tokensBetween(methodStartTokens, ETokenType.COLON,
088                                ETokenType.LBRACE);
089                return tokensAfterMethodName.stream()
090                                .filter(x -> x.getType() != ETokenType.LPAREN && x.getType() != ETokenType.RPAREN)
091                                .collect(Collectors.toList());
092
093        }
094
095}