001    /*
002     * Sonar, open source software quality management tool.
003     * Copyright (C) 2009 SonarSource SA
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.ast.visitor;
021    
022    import org.sonar.squid.api.AnalysisException;
023    import org.sonar.squid.api.SourceCode;
024    
025    import antlr.collections.AST;
026    
027    import com.puppycrawl.tools.checkstyle.api.DetailAST;
028    import com.puppycrawl.tools.checkstyle.api.Scope;
029    import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
030    import com.puppycrawl.tools.checkstyle.api.TokenTypes;
031    
032    public final class AstUtils {
033    
034      private AstUtils() {
035      }
036    
037      public static AST findType(DetailAST ast) {
038        DetailAST typeAst = ast.findFirstToken(TokenTypes.TYPE);
039        if (typeAst != null) {
040          return typeAst.getFirstChild();
041        }
042        return null;
043      }
044    
045      public static boolean isClassVariable(DetailAST ast) {
046        return ast.getType() == TokenTypes.VARIABLE_DEF && ast.getParent().getType() == TokenTypes.OBJBLOCK
047            && isClass(ast.getParent().getParent());
048      }
049    
050      public static boolean isClass(DetailAST ast) {
051        return ast.getType() == TokenTypes.CLASS_DEF || ast.getType() == TokenTypes.ENUM_DEF || ast.getType() == TokenTypes.ANNOTATION_DEF
052            || ast.getType() == TokenTypes.INTERFACE_DEF;
053      }
054    
055      public static boolean isInterfaceVariable(DetailAST ast) {
056        return ast.getType() == TokenTypes.VARIABLE_DEF && ast.getParent().getType() == TokenTypes.OBJBLOCK
057            && isInterface(ast.getParent().getParent());
058      }
059    
060      public static boolean isInterface(DetailAST ast) {
061        return ast.getType() == TokenTypes.INTERFACE_DEF;
062      }
063    
064      public static boolean isFinal(DetailAST detailAst) {
065        return isModifier(detailAst, TokenTypes.FINAL);
066      }
067    
068      public static boolean isStatic(DetailAST detailAst) {
069        return isModifier(detailAst, TokenTypes.LITERAL_STATIC);
070      }
071    
072      public static boolean isModifier(DetailAST detailAst, int modifierType) {
073        DetailAST modifiers = detailAst.findFirstToken(TokenTypes.MODIFIERS);
074        if (modifiers != null) {
075          boolean isModifierMatching = modifiers.branchContains(modifierType);
076          if (!isModifierMatching && isInterfaceVariable(detailAst)) {
077            // by default if not specified, a var def in an interface is
078            // public final static
079            return (modifierType == TokenTypes.LITERAL_STATIC || modifierType == TokenTypes.FINAL);
080          }
081          return isModifierMatching;
082        }
083        return false;
084      }
085    
086      public static Scope getScope(DetailAST ast) {
087        DetailAST modifierAst = ast.findFirstToken(TokenTypes.MODIFIERS);
088        Scope found = modifierAst != null ? ScopeUtils.getScopeFromMods(modifierAst) : Scope.NOTHING;
089        if (found.compareTo(Scope.PACKAGE) == 0 && (ast.getType() == TokenTypes.METHOD_DEF || ast.getType() == TokenTypes.VARIABLE_DEF)) {
090          // check if we found a parent interface declaration
091          // interface methods or var defs are by default public when not
092          // specified
093          found = (isScope(Scope.PACKAGE, found) && findParent(ast, TokenTypes.INTERFACE_DEF) != null) ? Scope.PUBLIC : found;
094        }
095        return found;
096      }
097    
098      public static boolean isScope(Scope toCompare, Scope scope) {
099        return scope.compareTo(toCompare) == 0;
100      }
101    
102      public static boolean isType(DetailAST ast, int type) {
103        return ast.getType() == type;
104      }
105    
106      public static DetailAST findParent(DetailAST ast, int tokenType) {
107        DetailAST parent = ast.getParent();
108        if (parent != null) {
109          return parent.getType() == tokenType ? parent : findParent(parent, tokenType);
110        }
111        return null;
112      }
113    
114      public static void ensureResourceType(SourceCode resource, Class<? extends SourceCode> resourceType) {
115        if (!resource.isType(resourceType)) {
116          throw new AnalysisException("Resource " + resource.getKey() + " must be of type " + resourceType.getName());
117        }
118      }
119    }