001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2008-2011 SonarSource
004     * mailto:contact AT sonarsource DOT com
005     *
006     * Sonar is free software; you can redistribute it and/or
007     * modify it under the terms of the GNU Lesser General Public
008     * License as published by the Free Software Foundation; either
009     * version 3 of the License, or (at your option) any later version.
010     *
011     * Sonar is distributed in the hope that it will be useful,
012     * but WITHOUT ANY WARRANTY; without even the implied warranty of
013     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     * Lesser General Public License for more details.
015     *
016     * You should have received a copy of the GNU Lesser General Public
017     * License along with Sonar; if not, write to the Free Software
018     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02
019     */
020    package org.sonar.java.signature;
021    
022    import java.util.ArrayList;
023    import java.util.List;
024    
025    public final class ParameterSignatureScanner {
026    
027      private final String signature;
028      private int index = 0;
029    
030      private static final char ARRAY = '[';
031    
032      private ParameterSignatureScanner(String parametersSignature) {
033        this.signature = parametersSignature;
034      }
035    
036      public static Parameter scan(String parameterSignature) {
037        ParameterSignatureScanner scanner = new ParameterSignatureScanner(parameterSignature);
038        if (scanner.hasNext()) {
039          return scanner.next();
040        } else {
041          return null;
042        }
043      }
044    
045      public static List<Parameter> scanArguments(String argumentsSignature) {
046        List<Parameter> arguments = new ArrayList<Parameter>();
047    
048        ParameterSignatureScanner scanner = new ParameterSignatureScanner(argumentsSignature);
049        while (scanner.hasNext()) {
050          arguments.add(scanner.next());
051        }
052    
053        return arguments;
054      }
055    
056      private boolean hasNext() {
057        if (signature.length() > index && (signature.charAt(index) == ARRAY || nextCharIsJvmJavaType())) {
058          return true;
059        }
060        return false;
061      }
062    
063      private boolean nextCharIsJvmJavaType() {
064        try {
065          JvmJavaType.valueOf(signature.substring(index, index + 1));
066          return true;
067        } catch (IllegalArgumentException e) {
068          return false;
069        }
070      }
071    
072      private Parameter next() {
073        boolean isArray = false;
074        String classCanonicalName = null;
075    
076        while (signature.charAt(index) == ARRAY) {
077          isArray = true;
078          index++;
079        }
080    
081        JvmJavaType jvmJavaType = JvmJavaType.valueOf(signature.substring(index, index + 1));
082        index = index + 1;
083    
084        if (jvmJavaType == JvmJavaType.L || jvmJavaType == JvmJavaType.T) {
085          int semicolonIndex = searchEndOfParameterSignature(signature, index);
086          int inferiorCharIndex = signature.indexOf('<', index);
087          if (inferiorCharIndex != -1 && inferiorCharIndex < semicolonIndex) {
088            classCanonicalName = signature.substring(index, signature.indexOf('<', index));
089          } else {
090            classCanonicalName = signature.substring(index, semicolonIndex);
091          }
092          index = semicolonIndex + 1;
093          jvmJavaType = JvmJavaType.L;
094        }
095        return new Parameter(jvmJavaType, classCanonicalName, isArray);
096      }
097    
098      private int searchEndOfParameterSignature(String signature, int index) {
099        int genericDefinitionStack = 0;
100        for (; index < signature.length(); index++) {
101          char character = signature.charAt(index);
102          if (character == ';' && genericDefinitionStack == 0) {
103            return index;
104          }
105          if (character == '<') {
106            genericDefinitionStack++;
107          } else if (character == '>') {
108            genericDefinitionStack--;
109          }
110        }
111        throw new IllegalStateException("Unable to extract parameter signature from '" + signature + "'");
112      }
113    }