001/*-----------------------------------------------------------------------+ 002 | com.teamscale.checks 003 | | 004 $Id$ 005 | | 006 | Copyright (c) 2009-2015 CQSE GmbH | 007 +-----------------------------------------------------------------------*/ 008package eu.cqse.check.java; 009 010import static eu.cqse.check.framework.scanner.ETokenType.DOT; 011import static eu.cqse.check.framework.scanner.ETokenType.IDENTIFIER; 012import static eu.cqse.check.framework.scanner.ETokenType.POINTERTO; 013import static eu.cqse.check.framework.scanner.ETokenType.SCOPE; 014 015import java.util.EnumSet; 016import java.util.List; 017 018import org.conqat.lib.commons.assertion.CCSMAssert; 019import org.conqat.lib.commons.collections.CollectionUtils; 020 021import eu.cqse.check.framework.scanner.ETokenType; 022import eu.cqse.check.framework.scanner.IToken; 023import eu.cqse.check.framework.shallowparser.TokenStreamTextUtils; 024 025/** 026 * Finds static method calls in token streams. 027 */ 028public class StaticMethodCallRecognizer { 029 030 /** 031 * The {@link ETokenType}s that are used for accessing a method of an object. 032 */ 033 private static final EnumSet<ETokenType> METHOD_CALL_TOKEN_TYPES = EnumSet.of(DOT, SCOPE, POINTERTO); 034 035 /** The full qualified method name. */ 036 private final String fullQualifiedName; 037 038 /** 039 * The sequence of token texts, that identifies the method in a token stream. 040 */ 041 private String[] recognitionSequence; 042 043 /** Constructor. */ 044 public StaticMethodCallRecognizer(String fullQualifiedMethodName) { 045 CCSMAssert.isNotNull(fullQualifiedMethodName); 046 this.fullQualifiedName = fullQualifiedMethodName; 047 initializeRecognitionSequence(); 048 } 049 050 /** Build the recognition sequence out of the full qualified method name. */ 051 private void initializeRecognitionSequence() { 052 String[] splitTokens = fullQualifiedName.split("\\."); 053 recognitionSequence = new String[splitTokens.length * 2]; 054 for (int i = 0; i < splitTokens.length; i++) { 055 int j = i * 2; 056 recognitionSequence[j] = splitTokens[i]; 057 if (i == splitTokens.length - 1) { 058 recognitionSequence[j + 1] = "("; 059 } else { 060 recognitionSequence[j + 1] = "."; 061 } 062 } 063 } 064 065 /** Returns all indices of method calls within the given tokens. */ 066 public List<Integer> findCallsInTokens(List<IToken> tokens) { 067 List<Integer> potentialCalls = TokenStreamTextUtils.findAllSequences(tokens, 0, IDENTIFIER, 068 recognitionSequence); 069 return CollectionUtils.filter(potentialCalls, 070 index -> atBeginningOrNotPreceededByMethodCallSeparator(tokens, index)); 071 } 072 073 /** 074 * Returns <code>true</code> if a system call is not preceded by one of the 075 * {@link #METHOD_CALL_TOKEN_TYPES}. 076 */ 077 private static boolean atBeginningOrNotPreceededByMethodCallSeparator(List<IToken> tokens, int index) { 078 if (index == 0) { 079 return true; 080 } 081 ETokenType previousType = tokens.get(index - 1).getType(); 082 return !METHOD_CALL_TOKEN_TYPES.contains(previousType); 083 } 084 085 /** Returns the length of the full qualified method name in tokens. */ 086 public int getTokenLength() { 087 return recognitionSequence.length - 1; 088 } 089 090 /** Returns a string representation of the full qualified method name. */ 091 public String getFullQualifiedMethodName() { 092 return fullQualifiedName; 093 } 094}