001/*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2008-2012 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 */
020package org.sonar.java.ast.visitor;
021
022import org.sonar.squid.api.AnalysisException;
023import org.sonar.squid.api.SourceCode;
024
025import antlr.collections.AST;
026
027import com.puppycrawl.tools.checkstyle.api.DetailAST;
028import com.puppycrawl.tools.checkstyle.api.Scope;
029import com.puppycrawl.tools.checkstyle.api.ScopeUtils;
030import com.puppycrawl.tools.checkstyle.api.TokenTypes;
031
032public 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}