/* * This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html. * * This file is a derivative of code released by the University of * California under the terms listed below. * * WALA JDT Frontend is Copyright (c) 2008 The Regents of the * University of California (Regents). Provided that this notice and * the following two paragraphs are included in any distribution of * Refinement Analysis Tools or its derivative work, Regents agrees * not to assert any of Regents' copyright rights in Refinement * Analysis Tools against recipient for recipient's reproduction, * preparation of derivative works, public display, public * performance, distribution or sublicensing of Refinement Analysis * Tools and derivative works, in source code and object code form. * This agreement not to assert does not confer, by implication, * estoppel, or otherwise any license or rights in any intellectual * property of Regents, including, but not limited to, any patents * of Regents or Regents' employees. * * IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, * INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE * AND ITS DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE AND FURTHER DISCLAIMS ANY STATUTORY * WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE AND ACCOMPANYING * DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS * IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, * UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ package com.ibm.wala.cast.java.translator.jdt; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Set; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.eclipse.jdt.core.dom.Assignment; import org.eclipse.jdt.core.dom.Assignment.Operator; import org.eclipse.jdt.core.dom.EnumDeclaration; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.InfixExpression; import org.eclipse.jdt.core.dom.Modifier; import org.eclipse.jdt.core.dom.TypeDeclaration; import com.ibm.wala.cast.tree.CAstQualifier; import com.ibm.wala.cast.tree.CAstSymbol; import com.ibm.wala.cast.tree.impl.CAstOperator; import com.ibm.wala.util.debug.Assertions; public class JDT2CAstUtils { public static Collection mapModifiersToQualifiers(int modifiers, boolean isInterface, boolean isAnnotation) { Set quals = new LinkedHashSet<>(); if (isInterface) quals.add(CAstQualifier.INTERFACE); if (isAnnotation) quals.add(CAstQualifier.ANNOTATION); if ((modifiers & Modifier.ABSTRACT) != 0) quals.add(CAstQualifier.ABSTRACT); if ((modifiers & Modifier.FINAL) != 0) quals.add(CAstQualifier.FINAL); if ((modifiers & Modifier.NATIVE) != 0) quals.add(CAstQualifier.NATIVE); // if (flags.isPackage()) quals.add(CAstQualifier.PACKAGE); if ((modifiers & Modifier.PRIVATE) != 0) quals.add(CAstQualifier.PRIVATE); if ((modifiers & Modifier.PROTECTED) != 0) quals.add(CAstQualifier.PROTECTED); if ((modifiers & Modifier.PUBLIC) != 0) quals.add(CAstQualifier.PUBLIC); if ((modifiers & Modifier.STATIC) != 0) quals.add(CAstQualifier.STATIC); if ((modifiers & Modifier.STRICTFP) != 0) quals.add(CAstQualifier.STRICTFP); if ((modifiers & Modifier.SYNCHRONIZED) != 0) quals.add(CAstQualifier.SYNCHRONIZED); if ((modifiers & Modifier.TRANSIENT) != 0) quals.add(CAstQualifier.TRANSIENT); if ((modifiers & Modifier.VOLATILE) != 0) quals.add(CAstQualifier.VOLATILE); return quals; } public static CAstOperator mapAssignOperator(Operator op) { if (op == Assignment.Operator.PLUS_ASSIGN) return CAstOperator.OP_ADD; else if (op == Assignment.Operator.BIT_AND_ASSIGN) return CAstOperator.OP_BIT_AND; else if (op == Assignment.Operator.BIT_OR_ASSIGN) return CAstOperator.OP_BIT_OR; else if (op == Assignment.Operator.BIT_XOR_ASSIGN) return CAstOperator.OP_BIT_XOR; else if (op == Assignment.Operator.DIVIDE_ASSIGN) return CAstOperator.OP_DIV; else if (op == Assignment.Operator.REMAINDER_ASSIGN) return CAstOperator.OP_MOD; else if (op == Assignment.Operator.TIMES_ASSIGN) return CAstOperator.OP_MUL; else if (op == Assignment.Operator.LEFT_SHIFT_ASSIGN) return CAstOperator.OP_LSH; else if (op == Assignment.Operator.RIGHT_SHIFT_SIGNED_ASSIGN) return CAstOperator.OP_RSH; else if (op == Assignment.Operator.MINUS_ASSIGN) return CAstOperator.OP_SUB; else if (op == Assignment.Operator.RIGHT_SHIFT_UNSIGNED_ASSIGN) return CAstOperator.OP_URSH; Assertions.UNREACHABLE("Unknown assignment operator"); return null; } protected static CAstOperator mapBinaryOpcode(InfixExpression.Operator operator) { if (operator == InfixExpression.Operator.PLUS) return CAstOperator.OP_ADD; // separate bitwise and logical AND / OR ? '&' / '|' ? if (operator == InfixExpression.Operator.AND) return CAstOperator.OP_BIT_AND; if (operator == InfixExpression.Operator.OR) return CAstOperator.OP_BIT_OR; if (operator == InfixExpression.Operator.XOR) return CAstOperator.OP_BIT_XOR; // TODO: shouldn't get here (conditional and handled differently); however should separate bitwise & logical '&' / '|', maybe. if (operator == InfixExpression.Operator.CONDITIONAL_AND) return CAstOperator.OP_REL_AND; if (operator == InfixExpression.Operator.CONDITIONAL_OR) return CAstOperator.OP_REL_OR; if (operator == InfixExpression.Operator.DIVIDE) return CAstOperator.OP_DIV; if (operator == InfixExpression.Operator.EQUALS) return CAstOperator.OP_EQ; if (operator == InfixExpression.Operator.GREATER_EQUALS) return CAstOperator.OP_GE; if (operator == InfixExpression.Operator.GREATER) return CAstOperator.OP_GT; if (operator == InfixExpression.Operator.LESS_EQUALS) return CAstOperator.OP_LE; if (operator == InfixExpression.Operator.LESS) return CAstOperator.OP_LT; if (operator == InfixExpression.Operator.REMAINDER) return CAstOperator.OP_MOD; if (operator == InfixExpression.Operator.TIMES) return CAstOperator.OP_MUL; if (operator == InfixExpression.Operator.NOT_EQUALS) return CAstOperator.OP_NE; if (operator == InfixExpression.Operator.LEFT_SHIFT) return CAstOperator.OP_LSH; if (operator == InfixExpression.Operator.RIGHT_SHIFT_SIGNED) return CAstOperator.OP_RSH; if (operator == InfixExpression.Operator.MINUS) return CAstOperator.OP_SUB; if (operator == InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED) return CAstOperator.OP_URSH; Assertions.UNREACHABLE("Java2CAstTranslator.JavaTranslatingVisitorImpl.mapBinaryOpcode(): unrecognized binary operator."); return null; } /** * Returns true if type is char, byte, short, int, or long. Return false otherwise (including boolean!) * * @param type */ public static boolean isLongOrLess(ITypeBinding type) { String t = type.getBinaryName(); return t.equals("C") || t.equals("B") || t.equals("S") || t.equals("I") || t.equals("J"); } /** * If isLongOrLess(type), returns Integer(0). If a float or double, returns Double(0.0) Otherwise (including boolean), returns * CAstSymbol.NULL_DEFAULT_VALUE. * * @param type */ public static Object defaultValueForType(ITypeBinding type) { if (isLongOrLess(type)) return Integer.valueOf(0); else if (type.getBinaryName().equals("D") || type.getBinaryName().equals("F")) return new Double(0.0); else return CAstSymbol.NULL_DEFAULT_VALUE; } public static ITypeBinding promoteTypes(ITypeBinding t1, ITypeBinding t2, AST ast) { // JLS 5.6.2 ITypeBinding doble = ast.resolveWellKnownType("double"); if (t1.equals(doble) || t2.equals(doble)) return doble; ITypeBinding flotando = ast.resolveWellKnownType("float"); if (t1.equals(flotando) || t2.equals(flotando)) return flotando; ITypeBinding largo = ast.resolveWellKnownType("long"); if (t1.equals(largo) || t2.equals(largo)) return largo; return ast.resolveWellKnownType("int"); } public static ITypeBinding getDeclaringClassOfNode(ASTNode n) { ASTNode current = n; while (current != null) { if (current instanceof TypeDeclaration) return ((TypeDeclaration) current).resolveBinding(); else if (current instanceof AnonymousClassDeclaration) return ((AnonymousClassDeclaration) current).resolveBinding(); else if (current instanceof EnumDeclaration) return ((EnumDeclaration) current).resolveBinding(); current = current.getParent(); } Assertions.UNREACHABLE("Couldn't find declaring class of node"); return null; } static String anonTypeName(ITypeBinding ct) { String binName = ct.getBinaryName(); String dollarSignNumber = binName.substring(binName.indexOf('$')); return "" + dollarSignNumber; } /** * If a type variable, return the bound (getTypeVariablesBase()). If a parameterized type, return the generic type. * * @param returnType * @param ast */ public static ITypeBinding getErasedType(ITypeBinding returnType, AST ast) { if (returnType.isTypeVariable() || returnType.isCapture()) return getTypesVariablesBase(returnType, ast); return returnType.getTypeDeclaration(); // Things like "Collection" are parameterized types... } public static ITypeBinding getTypesVariablesBase(ITypeBinding returnType, AST ast) { assert returnType.isTypeVariable() || returnType.isCapture(); if (returnType.getTypeBounds().length > 0) return returnType.getTypeBounds()[0]; // TODO: why is there more than one bound? else return ast.resolveWellKnownType("java.lang.Object"); } public static InfixExpression.Operator mapAssignOperatorToInfixOperator(Assignment.Operator op) { if (op == Assignment.Operator.PLUS_ASSIGN) return InfixExpression.Operator.PLUS; else if (op == Assignment.Operator.BIT_AND_ASSIGN) return InfixExpression.Operator.AND; else if (op == Assignment.Operator.BIT_OR_ASSIGN) return InfixExpression.Operator.OR; else if (op == Assignment.Operator.BIT_XOR_ASSIGN) return InfixExpression.Operator.XOR; else if (op == Assignment.Operator.DIVIDE_ASSIGN) return InfixExpression.Operator.DIVIDE; else if (op == Assignment.Operator.REMAINDER_ASSIGN) return InfixExpression.Operator.REMAINDER; else if (op == Assignment.Operator.TIMES_ASSIGN) return InfixExpression.Operator.TIMES; else if (op == Assignment.Operator.LEFT_SHIFT_ASSIGN) return InfixExpression.Operator.LEFT_SHIFT; else if (op == Assignment.Operator.RIGHT_SHIFT_SIGNED_ASSIGN) return InfixExpression.Operator.RIGHT_SHIFT_SIGNED; else if (op == Assignment.Operator.MINUS_ASSIGN) return InfixExpression.Operator.MINUS; else if (op == Assignment.Operator.RIGHT_SHIFT_UNSIGNED_ASSIGN) return InfixExpression.Operator.RIGHT_SHIFT_UNSIGNED; Assertions.UNREACHABLE("Unknown assignment operator"); return null; } private static void getMethodInClassOrSuperclass(IMethodBinding met, ITypeBinding klass, boolean superclassonly, HashMap overridden) { if (!superclassonly) { for (IMethodBinding ourmet : klass.getDeclaredMethods()) if (met.overrides(ourmet)) { overridden.put(ourmet.getMethodDeclaration().getReturnType(), ourmet.getMethodDeclaration()); break; // there can only be one per class so don't bother looking for more } } for (ITypeBinding iface : klass.getInterfaces()) getMethodInClassOrSuperclass(met, iface, false, overridden); ITypeBinding superclass = klass.getSuperclass(); if (superclass != null) getMethodInClassOrSuperclass(met, superclass, false, overridden); } public static Collection getOverriddenMethod(IMethodBinding met) { HashMap overridden = new HashMap<>(); if (met == null) return null; getMethodInClassOrSuperclass(met, met.getDeclaringClass(), true, overridden); if (overridden.size() == 0) return null; return overridden.values(); } public static boolean sameErasedSignatureAndReturnType(IMethodBinding met1, IMethodBinding met2) { if (!met1.getReturnType().getErasure().isEqualTo(met2.getReturnType().getErasure())) return false; ITypeBinding[] params1 = met1.getParameterTypes(); ITypeBinding[] params2 = met2.getParameterTypes(); if (params1.length != params2.length) return false; for (int i = 0; i < params1.length; i++) if (!params1[i].getErasure().isEqualTo(params2[i].getErasure())) return false; return true; } }