0001: /*
0002: * xtc - The eXTensible Compiler
0003: * Copyright (C) 2005-2007 IBM Corp.
0004: *
0005: * This program is free software; you can redistribute it and/or
0006: * modify it under the terms of the GNU General Public License
0007: * version 2 as published by the Free Software Foundation.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU General Public License
0015: * along with this program; if not, write to the Free Software
0016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
0017: * USA.
0018: */
0019: package xtc.lang;
0020:
0021: import java.io.CharArrayWriter;
0022: import java.io.File;
0023: import java.io.FileReader;
0024: import java.io.IOException;
0025: import java.io.Reader;
0026: import java.io.StringReader;
0027: import java.lang.reflect.Constructor;
0028: import java.lang.reflect.Method;
0029: import java.util.ArrayList;
0030: import java.util.Collections;
0031: import java.util.Formatter;
0032: import java.util.HashMap;
0033: import java.util.HashSet;
0034: import java.util.Iterator;
0035: import java.util.LinkedList;
0036: import java.util.List;
0037: import java.util.Map;
0038: import java.util.Set;
0039: import java.util.TreeSet;
0040:
0041: import xtc.Constants;
0042: import xtc.parser.ParseException;
0043: import xtc.parser.Result;
0044: import xtc.tree.Attribute;
0045: import xtc.tree.GNode;
0046: import xtc.tree.LineMarker;
0047: import xtc.tree.Location;
0048: import xtc.tree.Node;
0049: import xtc.tree.Printer;
0050: import xtc.tree.Visitor;
0051: import xtc.type.AliasT;
0052: import xtc.type.AnnotatedT;
0053: import xtc.type.ArrayT;
0054: import xtc.type.BooleanT;
0055: import xtc.type.ClassOrInterfaceT;
0056: import xtc.type.ClassT;
0057: import xtc.type.DynamicReference;
0058: import xtc.type.FunctionOrMethodT;
0059: import xtc.type.IntegerT;
0060: import xtc.type.InterfaceT;
0061: import xtc.type.MethodT;
0062: import xtc.type.NullReference;
0063: import xtc.type.NumberT;
0064: import xtc.type.PackageT;
0065: import xtc.type.Type;
0066: import xtc.type.TypePrinter;
0067: import xtc.type.VariableT;
0068: import xtc.type.VoidT;
0069: import xtc.type.WrappedT;
0070: import xtc.util.Runtime;
0071: import xtc.util.SymbolTable;
0072: import xtc.util.Utilities;
0073: import xtc.util.SymbolTable.Scope;
0074:
0075: /**
0076: * Common functionality for handling Java entities outside the AST.
0077: *
0078: * <p><u>Composite types</u>
0079: * <table border=0>
0080: * <tr><td>ExpressionT <td>> <td>GeneralLValueT, GeneralRValueT
0081: * <tr><td>GeneralLValueT <td>> <td><b>LValueT</b>, FieldT, LocalT, ParameterT
0082: * <tr><td><b>LValueT</b> <td>= <td>RValueT
0083: * <tr><td>FieldT <td>> <td><b>VariableT</b>:(FIELD Name WrappedRValueT)
0084: * <tr><td>LocalT <td>> <td><b>VariableT</b>:(LOCAL Name WrappedRValueT)
0085: * <tr><td>ParameterT <td>> <td><b>VariableT</b>:(PARAMETER Name RValueT)
0086: * <tr><td>GeneralRValueT <td>> <td><b>NullT</b>, WrappedRValueT
0087: * <tr><td>RValueT <td>> <td>PrimitiveT, <b>ArrayT</b>, WrappedClassT, WrappedInterfaceT
0088: * <tr><td><b>ArrayT</b> <td>= <td><b>LValueT</b>
0089: * <tr><td><b>ClassT</b> <td>= <td>Name WrappedClassT WrappedInterfaceT* Members
0090: * <tr><td><b>InterfaceT</b> <td>= <td>Name WrappedInterfaceT* Members
0091: * <tr><td>Members</b> <td>= <td>FieldT* MethodT* WrappedClassT* WrappedInterfaceT*
0092: * <tr><td><b>MethodT</b> <td>= <td>ReturnT Name ParameterT* WrappedClassT*
0093: * <tr><td>NotAValueT <td>> <td><b>PackageT</b>, <b>AnnotatedT</b>:ReturnT --- annotated with Constants.ATT_NOT_A_VALUE
0094: * <tr><td>ReturnT <td>> <td><b>VoidT</b>, RValueT
0095: * </table>
0096: *
0097: * <p><u>Wrapped types</u>
0098: * <table border=0>
0099: * <tr><td>WrappedRValueT</td> <td>> <td><b>ConstantT</b>:RValueT / RValueT
0100: * <tr><td>WrappedClassT</td> <td>> <td><b>AliasT</b>:Name / <b>AliasT</b>:<b>ClassT</b> / <b>ClassT</b>
0101: * <tr><td>WrappedInterfaceT</td> <td>> <td><b>AliasT</b>:Name / <b>AliasT</b>:<b>InterfaceT</b> / <b>InterfaceT</b>
0102: * </table>
0103: *
0104: * <p><u>Basetypes</u>
0105: * <table border=0>
0106: * <tr><td>PrimitiveT <td>> <td><b>BooleanT</b>, <b>NumberT</b>
0107: * <tr><td><b>NumberT</b> <td>> <td><b>IntegerT</b>, <b>FloatT</b>
0108: * <tr><td>NullT <td>= <td><b>ConstantT</b>:<b>VoidT</b>
0109: * </table>
0110: * </table>
0111: *
0112: * <p><u>Explanation</u>
0113: * <table border=0>
0114: * <tr><td><b>Bold font entities</b> <td>are represented explicitly in xtc.type
0115: * <tr><td><i>Super > Sub1, ..., SubN</i> <td>any of the <i>SubI</i> can appear where a <i>Super</i> is expected
0116: * <tr><td><i>Whole = Part1, ..., PartN</i> <td>the <i>Whole</i> consists of all the parts <i>PartI</i>
0117: * <tr><td><i>Whole = Part1 / ... / PartN</i> <td>the <i>Whole</i> consists of one of the parts <i>PartI</i>
0118: * <tr><td><i>Wrapper:Contents</i> <td>the <i>Wrapper</i> must wrap an instance of <i>Contents</i>
0119: * <tr><td><i>Repetee</i>* <td>zero or more occurences
0120: * </table>
0121: *
0122: * @author Martin Hirzel
0123: */
0124: public final class JavaEntities {
0125: public static final class JavaTypePrinter extends TypePrinter {
0126: private boolean _showDetails;
0127:
0128: private final SymbolTable _table;
0129:
0130: public JavaTypePrinter(final SymbolTable tab,
0131: final boolean showDetails, final Printer initPrinter) {
0132: super (initPrinter);
0133: _showDetails = showDetails;
0134: _table = tab;
0135: }
0136:
0137: private boolean isJavaLangObject(final Type t) {
0138: if (null == t)
0139: return false;
0140: if (t.isClass())
0141: return t.toClass().getQName()
0142: .equals("java.lang.Object");
0143: assert t.isAlias();
0144: final String n = t.toAlias().getName();
0145: return n.equals("Object") || n.equals("java.lang.Object");
0146: }
0147:
0148: public final boolean printAnnotations(final Type t) {
0149: printAttributes(t);
0150: return t.hasAttributes();
0151: }
0152:
0153: public final void printAttributes(final Type t) {
0154: if (t.hasAttributes())
0155: for (final Attribute att : t.attributes())
0156: printer.p(modifierToName(att)).p(' ');
0157: }
0158:
0159: private final void printMethodNoDetails(final MethodT t) {
0160: assert !_showDetails;
0161: dispatch(JavaEntities.declaringType(_table, t));
0162: printer.p('.').p(t.getName());
0163: }
0164:
0165: public final void printSignature(final FunctionOrMethodT t) {
0166: if (!_showDetails)
0167: throw new Error();
0168: _showDetails = false;
0169: printer.p('(');
0170: for (final Iterator<Type> iter = t.getParameters()
0171: .iterator(); iter.hasNext();) {
0172: printer.p(iter.next());
0173: if (iter.hasNext() || t.isVarArgs())
0174: printer.p(", ");
0175: }
0176: if (t.isVarArgs())
0177: printer.p("...");
0178: printer.p(") -> ");
0179: if (t.getResult().resolve().isFunction())
0180: printer.p('(').p(t.getResult()).p(')');
0181: else
0182: printer.p(t.getResult());
0183: if ((null != t.getExceptions())
0184: && (!t.getExceptions().isEmpty())) {
0185: printer.p(" throws ");
0186: for (Iterator<Type> iter = t.getExceptions().iterator(); iter
0187: .hasNext();) {
0188: printer.p(iter.next());
0189: if (iter.hasNext())
0190: printer.p(", ");
0191: }
0192: }
0193: _showDetails = true;
0194: }
0195:
0196: public final void visit(final AliasT t) {
0197: printer.p(t.getName());
0198: }
0199:
0200: public final void visit(final AnnotatedT t) {
0201: if (JavaEntities.isNullT(t)) {
0202: printer.p("null");
0203: return;
0204: }
0205: if (_showDetails)
0206: printAttributes(t);
0207: printer.p(t.getType());
0208: }
0209:
0210: public final void visit(final ArrayT t) {
0211: printer.p(arrayElementType(t)).p("[]");
0212: }
0213:
0214: public final void visit(final BooleanT t) {
0215: printer.p("boolean");
0216: }
0217:
0218: public final void visit(final ClassT t) {
0219: if (!_showDetails) {
0220: printer.p(t.getQName());
0221: return;
0222: }
0223: printAttributes(t);
0224: printer.p("class ").p(t.getQName());
0225: if (!isJavaLangObject(t.getParent()))
0226: printer.p(" extends ").p(t.getParent());
0227: if (!t.getInterfaces().isEmpty()) {
0228: printer.p(" implements ");
0229: for (final Iterator<Type> i = t.getInterfaces()
0230: .iterator(); i.hasNext();) {
0231: printer.p(i.next());
0232: if (i.hasNext())
0233: printer.p(", ");
0234: }
0235: }
0236: printer.p("{");
0237: final Scope scope = _table.getScope(typeToScopeName(t));
0238: final TreeSet<String> sortedMembers = new TreeSet<String>();
0239: for (final Iterator<String> i = scope.symbols(); i
0240: .hasNext();)
0241: sortedMembers.add(i.next());
0242: for (final String s : sortedMembers) {
0243: final Type m = (Type) scope.lookupLocally(s);
0244: assert null != m;
0245: dispatch(m);
0246: printer.p("; ");
0247: }
0248: printer.p("}");
0249: }
0250:
0251: public final void visit(final InterfaceT t) {
0252: if (!_showDetails) {
0253: printer.p(t.getQName());
0254: return;
0255: }
0256: printAttributes(t);
0257: printer.p("interface ").p(t.getQName());
0258: if (!t.getInterfaces().isEmpty()) {
0259: printer.p(" extends ");
0260: for (final Iterator<Type> i = t.getInterfaces()
0261: .iterator(); i.hasNext();) {
0262: printer.p(i.next());
0263: if (i.hasNext())
0264: printer.p(", ");
0265: }
0266: }
0267: printer.p("{");
0268: final Scope scope = _table.getScope(typeToScopeName(t));
0269: final TreeSet<String> sortedMembers = new TreeSet<String>();
0270: for (final Iterator<String> i = scope.symbols(); i
0271: .hasNext();)
0272: sortedMembers.add(i.next());
0273: for (final String s : sortedMembers) {
0274: final Type m = (Type) scope.lookupLocally(s);
0275: assert null != m;
0276: dispatch(m);
0277: printer.p("; ");
0278: }
0279: printer.p("}");
0280: }
0281:
0282: public final void visit(final MethodT t) {
0283: if (_showDetails)
0284: super .visit(t);
0285: else
0286: printMethodNoDetails(t);
0287: }
0288: }
0289:
0290: static class MiniVisitor_allUsedIdentifiers extends Visitor {
0291: public final Set<String> visit(final LineMarker m) {
0292: final Node n = m.getNode();
0293: return null == n ? EMPTY_SET : stringSet(dispatch(n));
0294: }
0295:
0296: public final Set<String> visit(final Node n) {
0297: final Set<String> result = new HashSet<String>();
0298: for (int i = 0; i < n.size(); i++) {
0299: if (n.get(i) instanceof String)
0300: result.add(n.getString(i));
0301: else if (n.get(i) instanceof Node)
0302: result.addAll(stringSet(dispatch(n.getNode(i))));
0303: }
0304: return result;
0305: }
0306:
0307: public final Set<String> visitBinaryExpression(final GNode n) {
0308: final Set<String> result = new HashSet<String>();
0309: result.addAll(stringSet(dispatch(n.getNode(0))));
0310: result.addAll(stringSet(dispatch(n.getNode(2))));
0311: return result;
0312: }
0313:
0314: public final Set<String> visitBlockDeclaration(final GNode n) {
0315: return stringSet(dispatch(n.getNode(1)));
0316: }
0317:
0318: public final Set<String> visitBooleanLiteral(final GNode n) {
0319: return EMPTY_SET;
0320: }
0321:
0322: public final Set<String> visitCharacterLiteral(final GNode n) {
0323: return EMPTY_SET;
0324: }
0325:
0326: public final Set<String> visitFieldDeclaration(final GNode n) {
0327: final Set<String> result = new HashSet<String>();
0328: result.addAll(stringSet(dispatch(n.getNode(1))));
0329: result.addAll(stringSet(dispatch(n.getNode(2))));
0330: return result;
0331: }
0332:
0333: public final Set<String> visitFloatingPointLiteral(final GNode n) {
0334: return EMPTY_SET;
0335: }
0336:
0337: public final Set<String> visitForInit(final GNode n) {
0338: if (1 == n.size())
0339: return stringSet(dispatch(n.getNode(0)));
0340: return stringSet(dispatch(n.getNode(1)));
0341: }
0342:
0343: public final Set<String> visitFormalParameter(final GNode n) {
0344: final Set<String> result = new HashSet<String>();
0345: result.addAll(stringSet(dispatch(n.getNode(1))));
0346: result.add(n.getString(3));
0347: return result;
0348: }
0349:
0350: public final Set<String> visitImportDeclaration(final GNode n) {
0351: return stringSet(dispatch(n.getNode(1)));
0352: }
0353:
0354: public final Set<String> visitIntegerLiteral(final GNode n) {
0355: return EMPTY_SET;
0356: }
0357:
0358: public final Set<String> visitNullLiteral(final GNode n) {
0359: return EMPTY_SET;
0360: }
0361:
0362: public final Set<String> visitPostfixUnaryExpression(
0363: final GNode n) {
0364: return stringSet(dispatch(n.getNode(0)));
0365: }
0366:
0367: public final Set<String> visitPrefixUnaryExpression(
0368: final GNode n) {
0369: return stringSet(dispatch(n.getNode(1)));
0370: }
0371:
0372: public final Set<String> visitStringLiteral(final GNode n) {
0373: return EMPTY_SET;
0374: }
0375:
0376: public final Set<String> visitType(final GNode n) {
0377: return stringSet(dispatch(n.getNode(0)));
0378: }
0379: }
0380:
0381: static class MiniVisitor_scrubLocations extends Visitor {
0382: public final void visit(final Node n) {
0383: n.setLocation((Location) null);
0384: for (final Object o : n)
0385: if (o instanceof Node)
0386: dispatch((Node) o);
0387: }
0388: }
0389:
0390: /**
0391: * Enumerates all the types from which this type may inherit methods or
0392: * fields. For classes and interfaces, this means all reflexive or transitive
0393: * super-classes/insterfaces. For arrays, this means Object, Cloneable, or
0394: * Serializable. This iterator will resolve any aliases it encounters on the
0395: * way. This iterator only applies to reference types.
0396: */
0397: static final class SuperTypesIter implements Iterator<Type> {
0398: private static String key(final Type type) {
0399: final Type t = type.isAlias() ? ((AliasT) type).getType()
0400: : type;
0401: if (t.isArray())
0402: return key(JavaEntities.arrayElementType(t.toArray()))
0403: + "[]";
0404: if (JavaEntities.isPrimitiveT(type))
0405: return type.toString();
0406: return JavaEntities.resolveToRawClassOrInterfaceT(t)
0407: .getQName();
0408: }
0409:
0410: private final List<File> _paths;
0411:
0412: /** Set of String keys: current and former contents of todo. */
0413: private final Set<String> _seen = new HashSet<String>();
0414:
0415: private final SymbolTable _tab;
0416:
0417: /** List of Types; add to end, remove from front. */
0418: private final LinkedList<Type> _todo = new LinkedList<Type>();
0419:
0420: public SuperTypesIter(final SymbolTable tab,
0421: final List<File> paths, final Type start) {
0422: this (tab, paths, start, true);
0423: }
0424:
0425: public SuperTypesIter(final SymbolTable tab,
0426: final List<File> paths, final Type start,
0427: final boolean reflexive) {
0428: _tab = tab;
0429: _paths = paths;
0430: final Type rStart = JavaEntities.resolveToRValue(start);
0431: if (reflexive)
0432: add(rStart);
0433: else
0434: addDirectSupertypes(rStart);
0435: }
0436:
0437: private final void add(final Type type) {
0438: assert null != type;
0439: assert JavaEntities.isReferenceT(type);
0440: if (_seen.add(key(type)))
0441: _todo.addLast(type);
0442: }
0443:
0444: private void addDirectSupertypes(final Type sub) {
0445: for (final ClassOrInterfaceT sup : JavaEntities
0446: .directSuperTypes(_tab, _paths, sub))
0447: add(sup);
0448: }
0449:
0450: public final boolean hasNext() {
0451: return !_todo.isEmpty();
0452: }
0453:
0454: public final Type next() {
0455: if (_todo.isEmpty())
0456: return null;
0457: final Type result = _todo.removeFirst();
0458: addDirectSupertypes(result);
0459: return result;
0460: }
0461:
0462: public final void remove() {
0463: throw new UnsupportedOperationException();
0464: }
0465: }
0466:
0467: public static final class UnicodeUnescaper extends Reader {
0468: private boolean _havePeek;
0469: private int _peek;
0470: private final Reader _reader;
0471:
0472: public UnicodeUnescaper(final Reader reader) {
0473: _havePeek = false;
0474: _peek = -1;
0475: _reader = reader;
0476: }
0477:
0478: public final void close() throws IOException {
0479: _reader.close();
0480: }
0481:
0482: public final int read() throws IOException {
0483: if (_havePeek) {
0484: _havePeek = false;
0485: return _peek;
0486: }
0487: final int a = _reader.read();
0488: if ('\\' != a)
0489: return a;
0490: _peek = _reader.read();
0491: if ('u' != _peek) {
0492: _havePeek = true;
0493: return a;
0494: }
0495: int curr = _peek;
0496: while ('u' == curr)
0497: curr = _reader.read();
0498: final byte[] digits = new byte[4];
0499: for (int i = 0; i < 4; i++) {
0500: if (0 != i)
0501: curr = _reader.read();
0502: switch (curr) {
0503: case '0':
0504: case '1':
0505: case '2':
0506: case '3':
0507: case '4':
0508: case '5':
0509: case '6':
0510: case '7':
0511: case '8':
0512: case '9':
0513: digits[i] = (byte) (curr - '0');
0514: break;
0515: case 'a':
0516: case 'b':
0517: case 'c':
0518: case 'd':
0519: case 'e':
0520: case 'f':
0521: digits[i] = (byte) (10 + curr - 'a');
0522: break;
0523: case 'A':
0524: case 'B':
0525: case 'C':
0526: case 'D':
0527: case 'E':
0528: case 'F':
0529: digits[i] = (byte) (10 + curr - 'A');
0530: break;
0531: default:
0532: throw new Error("illegal unicode sequence");
0533: }
0534: }
0535: int result = 0;
0536: for (int i = 0; i < 4; i++)
0537: result = (result << 4) | digits[i];
0538: return result;
0539: }
0540:
0541: public final int read(final char[] cbuf, final int off,
0542: final int len) throws IOException {
0543: int result = 0;
0544: while (result < len) {
0545: final int c = read();
0546: if (-1 == c)
0547: return -1;
0548: cbuf[off + result] = (char) c;
0549: result++;
0550: }
0551: return result;
0552: }
0553: }
0554:
0555: public static final Set<String> EMPTY_SET = Collections.emptySet();
0556:
0557: private static final Map<Attribute, String> MODIFIER_TO_NAME = new HashMap<Attribute, String>();
0558:
0559: private static final Map<String, Type> NAME_TO_BASETYPE = new HashMap<String, Type>();
0560:
0561: private static final Map<String, Attribute> NAME_TO_MODIFIER = new HashMap<String, Attribute>();
0562:
0563: private static boolean recursiveTypeDotType = false;
0564:
0565: static {
0566: NAME_TO_MODIFIER.put("public", Constants.ATT_PUBLIC);
0567: NAME_TO_MODIFIER.put("protected", Constants.ATT_PROTECTED);
0568: NAME_TO_MODIFIER.put("private", Constants.ATT_PRIVATE);
0569: NAME_TO_MODIFIER.put("static", Constants.ATT_STORAGE_STATIC);
0570: NAME_TO_MODIFIER.put("abstract", Constants.ATT_ABSTRACT);
0571: NAME_TO_MODIFIER.put("final", Constants.ATT_CONSTANT);
0572: NAME_TO_MODIFIER.put("native", Constants.ATT_NATIVE);
0573: NAME_TO_MODIFIER
0574: .put("synchronized", Constants.ATT_SYNCHRONIZED);
0575: NAME_TO_MODIFIER.put("transient", Constants.ATT_TRANSIENT);
0576: NAME_TO_MODIFIER.put("volatile", Constants.ATT_VOLATILE);
0577: NAME_TO_MODIFIER.put("strictfp", Constants.ATT_STRICT_FP);
0578: for (final Map.Entry<String, Attribute> e : NAME_TO_MODIFIER
0579: .entrySet())
0580: MODIFIER_TO_NAME.put(e.getValue(), e.getKey());
0581: NAME_TO_BASETYPE.put("boolean", BooleanT.TYPE);
0582: NAME_TO_BASETYPE.put("byte", NumberT.BYTE);
0583: NAME_TO_BASETYPE.put("char", NumberT.CHAR);
0584: NAME_TO_BASETYPE.put("double", NumberT.DOUBLE);
0585: NAME_TO_BASETYPE.put("float", NumberT.FLOAT);
0586: NAME_TO_BASETYPE.put("int", NumberT.INT);
0587: NAME_TO_BASETYPE.put("long", NumberT.LONG);
0588: NAME_TO_BASETYPE.put("null", VoidT.TYPE.annotate().constant(
0589: NullReference.NULL));
0590: NAME_TO_BASETYPE.put("short", NumberT.SHORT);
0591: NAME_TO_BASETYPE.put("void", VoidT.TYPE);
0592: }
0593:
0594: public static void addBaseTypes(final SymbolTable tab) {
0595: if (null == tab.lookup("int")) {
0596: final String oldScope = JavaEntities
0597: .enterScopeByQualifiedName(tab, "");
0598: for (final String name : NAME_TO_BASETYPE.keySet())
0599: tab.current().define(name, nameToBaseType(name));
0600: JavaEntities.enterScopeByQualifiedName(tab, oldScope);
0601: }
0602: }
0603:
0604: public static List<MethodT> allAbstractMethods(
0605: final SymbolTable tab, final List<File> paths,
0606: final ClassT clazz) {
0607: final List<MethodT> all = allMethods(tab, paths, clazz);
0608: final List<MethodT> specific = mostSpecificMethods(tab, paths,
0609: all);
0610: final List<MethodT> result = new ArrayList<MethodT>();
0611: for (final MethodT method : specific)
0612: if (hasModifier(method, "abstract"))
0613: result.add(method);
0614: return result;
0615: }
0616:
0617: public static List<MethodT> allMethods(final SymbolTable tab,
0618: final List<File> paths, final ClassT base) {
0619: final List<MethodT> result = new ArrayList<MethodT>();
0620: for (final Iterator<Type> i = new SuperTypesIter(tab, paths,
0621: base); i.hasNext();)
0622: result.addAll(methodsOwn(i.next()));
0623: return result;
0624: }
0625:
0626: public static Set<String> allUsedIdentifiers(final GNode ast) {
0627: final MiniVisitor_allUsedIdentifiers v = new MiniVisitor_allUsedIdentifiers();
0628: final Set<String> result = stringSet(v.dispatch(ast));
0629: return result;
0630: }
0631:
0632: public static Type arrayElementType(final ArrayT arrayT) {
0633: final AnnotatedT l = (AnnotatedT) arrayT.getType();
0634: final Type result = l.getType();
0635: assert isRValueT(result);
0636: return result;
0637: }
0638:
0639: public static VariableT arrayLengthField() {
0640: final VariableT result = VariableT.newField(
0641: nameToBaseType("int"), "length");
0642: result.addAttribute(nameToModifier("final"));
0643: result.addAttribute(nameToModifier("public"));
0644: result.scope(".package(java.lang).file().Object");
0645: assert isFieldT(result);
0646: return result;
0647: }
0648:
0649: public static String baseTypeToName(final Type baseType) {
0650: return typeToString(null, false, baseType);
0651: }
0652:
0653: public static ClassOrInterfaceT canonicalAliasToType(
0654: final SymbolTable tab, final List<File> paths,
0655: final AliasT alias, final boolean mayBeInUnnamedPackage) {
0656: if (alias.getType() == null)
0657: alias.setType(canonicalNameToType(tab, paths, alias
0658: .getName(), mayBeInUnnamedPackage));
0659: return (ClassOrInterfaceT) alias.getType();
0660: }
0661:
0662: public static String canonicalName(final SymbolTable tab,
0663: final String simpleName) {
0664: final ClassOrInterfaceT enclosingClass = currentType(tab);
0665: if (enclosingClass != null)
0666: return Utilities.qualify(enclosingClass.getQName(),
0667: simpleName);
0668: final PackageT enclosingPackage = currentPackage(tab);
0669: if (enclosingPackage == null) {
0670: final Error e = new Error();
0671: e.printStackTrace();
0672: throw e;
0673: }
0674: if ("".equals(enclosingPackage.getName()))
0675: return simpleName;
0676: return Utilities
0677: .qualify(enclosingPackage.getName(), simpleName);
0678: }
0679:
0680: public static PackageT canonicalNameToPackage(
0681: final SymbolTable tab, final String name) {
0682: if (name.indexOf('.') == -1)
0683: return simpleNameToPackage(tab, name);
0684: final PackageT base = canonicalNameToPackage( //
0685: tab, Utilities.getQualifier(name));
0686: return packageDotPackage(tab, base, Utilities.unqualify(name));
0687: }
0688:
0689: public static Type canonicalNameToPackageOrType(
0690: final SymbolTable tab, final List<File> paths,
0691: final String name, final boolean mayBeInUnnamedPackage) {
0692: final Type t = canonicalNameToType(tab, paths, name,
0693: mayBeInUnnamedPackage);
0694: return t != null ? t : canonicalNameToPackage(tab, name);
0695: }
0696:
0697: public static ClassOrInterfaceT canonicalNameToType(
0698: final SymbolTable tab, final List<File> paths,
0699: final String name, final boolean mayBeInUnnamedPackage) {
0700: if (name.indexOf('.') == -1) {
0701: if (mayBeInUnnamedPackage)
0702: return packageDotType(tab, paths, simpleNameToPackage(
0703: tab, ""), name);
0704: return null;
0705: }
0706: final String qualifier = Utilities.getQualifier(name);
0707: final String selector = Utilities.unqualify(name);
0708: if (qualifier.indexOf('.') == -1)
0709: return packageDotType(tab, paths, simpleNameToPackage(tab,
0710: qualifier), selector);
0711: final Type base = canonicalNameToPackageOrType(tab, paths,
0712: qualifier, mayBeInUnnamedPackage);
0713: if (base.isPackage())
0714: return packageDotType(tab, paths, base.toPackage(),
0715: selector);
0716: return typeDotType(tab, paths, (ClassOrInterfaceT) base, false,
0717: selector);
0718: }
0719:
0720: public static List<File> classpath(final Runtime runtime) {
0721: return runtime.getFileList(Runtime.INPUT_DIRECTORY);
0722: }
0723:
0724: public static boolean constructorsReturnVoid() {
0725: return true;
0726: }
0727:
0728: /** Can only create concrete subclass that implements all abstract methods if there
0729: * is no pair of abstract methods with the same signature, but different return types. */
0730: public static boolean couldCreateConcreteSubclass(
0731: final SymbolTable tab, final List<File> paths,
0732: final ClassT clazz) {
0733: final List<MethodT> abstractMethods = allAbstractMethods(tab,
0734: paths, clazz);
0735: for (final MethodT m : abstractMethods)
0736: resolveIfAliasMethod(tab, paths, m);
0737: for (final MethodT m1 : abstractMethods)
0738: for (final MethodT m2 : abstractMethods)
0739: if (m1.getName().equals(m2.getName())
0740: && sameMethodSignature(m1, m2))
0741: if (!JavaTypeConverter.isIdentical(m1.getResult(),
0742: m2.getResult()))
0743: return false;
0744: return true;
0745: }
0746:
0747: public static List<Type> currentImports(final SymbolTable tab) {
0748: for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s
0749: .getParent()) {
0750: final String n = s.getName();
0751: if (SymbolTable.isInNameSpace(n, "file"))
0752: return imports(tab, currentPackage(tab), SymbolTable
0753: .fromNameSpace(n));
0754: }
0755: return imports(tab, null, null);
0756: }
0757:
0758: public static MethodT currentMethod(final SymbolTable tab) {
0759: for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s
0760: .getParent()) {
0761: final String name = s.getName();
0762: if (SymbolTable.isInNameSpace(name, "method")) {
0763: final ClassOrInterfaceT type = currentType(tab);
0764: for (final Type method : type.getMethods()) {
0765: assert method.isMethod();
0766: final String s2;
0767: assert method.hasScope(false);
0768: s2 = method.getScope();
0769: if (s.getQualifiedName().equals(s2))
0770: return method.toMethod();
0771: }
0772: }
0773: }
0774: return null;
0775: }
0776:
0777: public static PackageT currentPackage(final SymbolTable tab) {
0778: for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s
0779: .getParent()) {
0780: final String n = s.getName();
0781: if (n.startsWith("package("))
0782: return canonicalNameToPackage(tab, SymbolTable
0783: .fromNameSpace(n));
0784: }
0785: return canonicalNameToPackage(tab, "");
0786: }
0787:
0788: public static ClassOrInterfaceT currentType(final SymbolTable tab) {
0789: for (SymbolTable.Scope s = tab.current(); !s.isRoot(); s = s
0790: .getParent()) {
0791: final String tagName = SymbolTable.toTagName(s.getName());
0792: final ClassOrInterfaceT result = (ClassOrInterfaceT) s
0793: .getParent().lookup(tagName);
0794: if (result != null)
0795: return result;
0796: }
0797: return null;
0798: }
0799:
0800: public static PackageT declaringPackage(final SymbolTable tab,
0801: final Type type) {
0802: if (type.isPackage())
0803: return (PackageT) type;
0804: if (type instanceof ClassOrInterfaceT
0805: && isTypeTopLevel((ClassOrInterfaceT) type)) {
0806: final String oldScope = enterScopeByQualifiedName(tab,
0807: typeToScopeName(type));
0808: final PackageT result = currentPackage(tab);
0809: enterScopeByQualifiedName(tab, oldScope);
0810: return result;
0811: }
0812: if (isTypeMember(type))
0813: return declaringPackage(tab, declaringType(tab, type));
0814: final String oldScope = enterScopeByQualifiedName(tab,
0815: declaringScopeName(type));
0816: final PackageT result = currentPackage(tab);
0817: enterScopeByQualifiedName(tab, oldScope);
0818: return result;
0819: }
0820:
0821: public static String declaringScopeName(final Type type) {
0822: assert !type.isAlias();
0823: final Type u = isConstantT(type) ? ((AnnotatedT) type)
0824: .getType() : type;
0825: if (u.hasScope(false)) {
0826: final String ownScope = u.getScope();
0827: if (isLocalT(type) || isParameterT(type) || isFieldT(type))
0828: return ownScope;
0829: return Utilities.getQualifier(ownScope);
0830: }
0831: return null;
0832: }
0833:
0834: public static ClassOrInterfaceT declaringType(
0835: final SymbolTable tab, final Type member) {
0836: assert member.isMethod() || isFieldT(member)
0837: || isWrappedClassT(member)
0838: || isWrappedInterfaceT(member);
0839: final String declaringScope = declaringScopeName(member);
0840: assert null != declaringScope;
0841: assert isScopeForMember(declaringScope);
0842: final String oldScope = enterScopeByQualifiedName(tab,
0843: declaringScope);
0844: final ClassOrInterfaceT result = currentType(tab);
0845: assert null != result;
0846: enterScopeByQualifiedName(tab, oldScope);
0847: return result;
0848: }
0849:
0850: public static Type dereference(final Type generalLValue) {
0851: assert isGeneralLValueT(generalLValue);
0852: final WrappedT wrapped = isLValueT(generalLValue) ? (AnnotatedT) generalLValue
0853: : resolveToRawLValue(generalLValue);
0854: final Type result = wrapped.getType();
0855: assert isGeneralRValueT(result);
0856: return result;
0857: }
0858:
0859: public static List<ClassOrInterfaceT> directSuperTypes(
0860: final SymbolTable tab, final List<File> paths,
0861: final Type sub) {
0862: if (sub.isArray()) {
0863: final List<ClassOrInterfaceT> result = new ArrayList<ClassOrInterfaceT>();
0864: result.add(JavaEntities.tObject(tab));
0865: result.add(JavaEntities.tCloneable(tab));
0866: result.add(JavaEntities.tSerializable(tab));
0867: return result;
0868: }
0869: final ClassOrInterfaceT rawSub = JavaEntities
0870: .resolveToRawClassOrInterfaceT(sub);
0871: final List<AliasT> aliases = new ArrayList<AliasT>();
0872: if (JavaEntities.isWrappedClassT(sub)) {
0873: final Type sup = rawSub.toClass().getParent();
0874: if (null != sup)
0875: aliases.add(sup.toAlias());
0876: }
0877: for (final Type i : rawSub.getInterfaces())
0878: aliases.add(i.toAlias());
0879: final String scope = JavaEntities.typeToScopeName(sub);
0880: return JavaEntities.qualifiedAliasesToTypes(tab, paths, scope,
0881: aliases);
0882: }
0883:
0884: public static String enterScopeByQualifiedName(
0885: final SymbolTable tab, final String name) {
0886: final String oldScopeName = tab.current().getQualifiedName();
0887: assert null != name;
0888: tab.setScope(tab.getScope(name));
0889: return oldScopeName;
0890: }
0891:
0892: public static List<VariableT> fieldsApplicableAndAccessible(
0893: final SymbolTable tab, final List<File> paths,
0894: final Type base, final boolean parents, final String name) {
0895: final List<VariableT> fields = parents ? fieldsOwnAndInherited(
0896: tab, paths, base) : fieldsOwn(base);
0897: final List<VariableT> result = new ArrayList<VariableT>();
0898: for (final VariableT field : fields)
0899: if (isAccessibleIn(tab, paths, field, base))
0900: if (isApplicableField(tab, paths, field, name))
0901: result.add(field);
0902: return result;
0903: }
0904:
0905: public static List<VariableT> fieldsInherited(
0906: final SymbolTable tab, final List<File> paths,
0907: final Type base) {
0908: //gosling_et_al_2000 8.3 (before subsections)
0909: final List<VariableT> result = new ArrayList<VariableT>();
0910: final List<VariableT> fieldsOwn = fieldsOwn(base);
0911: final String baseScope = declaringScopeName(base);
0912: assert null != baseScope || base.isArray();
0913: final List<ClassOrInterfaceT> super Types = directSuperTypes(
0914: tab, paths, base);
0915: for (final ClassOrInterfaceT super Type : super Types) {
0916: final List<VariableT> super Fields = fieldsOwnAndInherited(
0917: tab, paths, super Type);
0918: super Fields: for (final VariableT f : super Fields) {
0919: if (hasModifier(f, "private"))
0920: continue super Fields;
0921: if (null != baseScope
0922: && !isAccessibleFromIn(tab, paths, baseScope,
0923: f, super Type))
0924: continue super Fields;
0925: for (final VariableT o : fieldsOwn)
0926: if (f.getName().equals(o.getName()))
0927: continue super Fields;
0928: for (final VariableT r : result)
0929: if (f == r)
0930: continue super Fields;
0931: result.add(f);
0932: }
0933: }
0934: return result;
0935: }
0936:
0937: public static List<VariableT> fieldsOwn(final Type base) {
0938: final List<VariableT> result = new ArrayList<VariableT>(1);
0939: if (base.isArray())
0940: result.add(arrayLengthField());
0941: else
0942: for (final Type f : resolveToRawClassOrInterfaceT(base)
0943: .getFields())
0944: result.add(f.toVariable());
0945: return result;
0946: }
0947:
0948: public static List<VariableT> fieldsOwnAndInherited(
0949: final SymbolTable tab, final List<File> paths,
0950: final Type base) {
0951: final List<VariableT> result = new ArrayList<VariableT>();
0952: result.addAll(fieldsInherited(tab, paths, base));
0953: result.addAll(fieldsOwn(base));
0954: return result;
0955: }
0956:
0957: public static String fileNameToScopeName(final String absolutePath) {
0958: return SymbolTable.toNameSpace(absolutePath, "file");
0959: }
0960:
0961: /** Does the class or one of its superclasses declare any abstract methods
0962: * that have not been implemented here or in a superclass? (gosling_et_al_2000 <a
0963: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#34944">§8.1.1</a>). */
0964: public static boolean hasAbstractMethods(final SymbolTable tab,
0965: final List<File> paths, final ClassT clazz) {
0966: return !allAbstractMethods(tab, paths, clazz).isEmpty();
0967: }
0968:
0969: /** Does the class depend on itself by inheritance or by nesting? (gosling_et_al_2000 <a
0970: * href="http://java.sun.com/docs/books/jls/second_edition/html/classes.doc.html#262560">§8.1.3</a>). */
0971: public static boolean hasCircularDependency(final SymbolTable tab,
0972: final List<File> paths, final ClassOrInterfaceT type) {
0973: final Iterator<Type> iSup = new SuperTypesIter(tab, paths,
0974: type, false);
0975: while (iSup.hasNext()) {
0976: Type t = iSup.next();
0977: inner: while (true) {
0978: if (JavaTypeConverter.isIdentical(type, t))
0979: return true;
0980: if (!isTypeMember(t))
0981: break inner;
0982: t = declaringType(tab, t);
0983: }
0984: }
0985: return false;
0986: }
0987:
0988: public static boolean hasModifier(final Type t, final String m) {
0989: final Type u = t.isAlias() ? ((AliasT) t).getType() : t;
0990: assert isGeneralLValueT(u) || u.isMethod() || u.isClass()
0991: || u.isInterface();
0992: return u.hasAttribute(nameToModifier(m), false);
0993: }
0994:
0995: static List<Type> imports(final SymbolTable tab,
0996: final PackageT packageT, final String fileName) {
0997: final String baseScope = null == packageT ? "" : scopeName(
0998: packageT, fileName);
0999: final Object o = tab.lookup(Utilities.qualify(baseScope,
1000: "imports(*)"));
1001: if (null == o)
1002: return new ArrayList<Type>();
1003: if (o instanceof List)
1004: return typeList((List) o);
1005: final ArrayList<Type> list = new ArrayList<Type>();
1006: list.add((Type) o);
1007: return list;
1008: }
1009:
1010: /** Is it allowed to use the entity from the current scope of the symbol table (gosling_et_al_2000 <a
1011: * href="http://java.sun.com/docs/books/jls/second_edition/html/names.doc.html#104285">§6.6</a>)? */
1012: public static boolean isAccessible(final SymbolTable tab,
1013: final List<File> paths, final Type entity) {
1014: return isAccessibleIn(tab, paths, entity, null);
1015: }
1016:
1017: public static boolean isAccessibleFromIn(final SymbolTable tab,
1018: final List<File> paths, final String scope,
1019: final Type entity, final Type inType) {
1020: final String oldScope = JavaEntities.enterScopeByQualifiedName(
1021: tab, scope);
1022: final boolean result = isAccessibleIn(tab, paths, entity,
1023: inType);
1024: JavaEntities.enterScopeByQualifiedName(tab, oldScope);
1025: return result;
1026: }
1027:
1028: public static boolean isAccessibleIn(final SymbolTable tab,
1029: final List<File> paths, final Type entity, final Type inType) {
1030: if (entity.isArray())
1031: return true;
1032: if (entity.isAlias())
1033: return isAccessible(tab, paths, ((AliasT) entity).getType());
1034: if (entity.isPackage())
1035: return true;
1036: final boolean samePackage = declaringPackage(tab, entity)
1037: .getName().equals(currentPackage(tab).getName());
1038: if (isWrappedClassT(entity) || isWrappedInterfaceT(entity)) {
1039: if (hasModifier(entity, "public"))
1040: return true;
1041: if (isTypeTopLevel((ClassOrInterfaceT) entity))
1042: return samePackage;
1043: }
1044: if (!isTypeMember(entity))
1045: return true;
1046: final Type base = null == inType ? declaringType(tab, entity)
1047: : inType;
1048: assert null != base;
1049: if (!isAccessible(tab, paths, base))
1050: return false;
1051: if (hasModifier(entity, "public"))
1052: return true;
1053: if (hasModifier(entity, "protected")) {
1054: if (samePackage)
1055: return true;
1056: if (entity.isMethod()
1057: && isConstructor(base, entity.toMethod())) {
1058: return false; //TD 36 (6.6.2) isAccessibleIn() for protected constructors in different package
1059: } else {
1060: final Type decl = declaringType(tab, entity), curr = currentType(tab);
1061: return (null == curr || isSuperClass(tab, paths, decl,
1062: curr))
1063: && isSuperClass(tab, paths, decl, base);
1064: }
1065: }
1066: if (hasModifier(entity, "private")) {
1067: final Type top;
1068: final String oldScope = enterScopeByQualifiedName(tab,
1069: typeToScopeName(base));
1070: while (true) {
1071: final ClassOrInterfaceT t = JavaEntities
1072: .currentType(tab);
1073: enterScopeByQualifiedName(tab, typeToScopeName(t));
1074: if (isTypeTopLevel(t)) {
1075: top = t;
1076: break;
1077: }
1078: tab.exit();
1079: }
1080: enterScopeByQualifiedName(tab, oldScope);
1081: return tab.current().getQualifiedName().startsWith(
1082: typeToScopeName(top));
1083: }
1084: return samePackage;
1085: }
1086:
1087: public static boolean isApplicableField(final SymbolTable tab,
1088: final List<File> paths, final VariableT field,
1089: final String name) {
1090: if (name.equals(field.getName())) {
1091: final ClassOrInterfaceT declaringType = declaringType(tab,
1092: field);
1093: resolveIfAlias(tab, paths, typeToScopeName(declaringType),
1094: field.getType());
1095: return true;
1096: }
1097: return false;
1098: }
1099:
1100: public static boolean isApplicableMemberType(final Type memberType,
1101: final String name) {
1102: final ClassOrInterfaceT raw = resolveToRawClassOrInterfaceT(memberType);
1103: return name.equals(raw.getName());
1104: }
1105:
1106: public static boolean isApplicableMethod(final SymbolTable tab,
1107: final List<File> paths, final MethodT callee,
1108: final String name, final List<Type> actuals) {
1109: if (!callee.getName().equals(name))
1110: return false;
1111: final List<Type> formals = callee.getParameters();
1112: if (formals.size() != actuals.size())
1113: return false;
1114: final ClassOrInterfaceT declaringType = declaringType(tab,
1115: callee);
1116: final String aScope = tab.current().getQualifiedName();
1117: final Iterator<Type> iF = formals.iterator(), iA = actuals
1118: .iterator();
1119: while (iF.hasNext()) {
1120: final Type formal = iF.next();
1121: resolveIfAlias(tab, paths, typeToScopeName(declaringType),
1122: dereference(formal));
1123: final Type aAlias = iA.next();
1124: final Type actual = resolveIfAlias(tab, paths, aScope,
1125: aAlias);
1126: final boolean conv = JavaTypeConverter.isParameterPassable(
1127: tab, paths, dereference(formal), actual);
1128: if (!conv)
1129: return false;
1130: }
1131: return true;
1132: }
1133:
1134: public static boolean isCheckedException(final SymbolTable tab,
1135: final List<File> paths, final Type exc) {
1136: // gosling_et_al_2000 11.2
1137: return isSuperClass(tab, paths, tThrowable(tab), exc)
1138: && !isSuperClass(tab, paths, tRuntimeException(tab),
1139: exc)
1140: && !isSuperClass(tab, paths, tError(tab), exc);
1141: }
1142:
1143: public static boolean isConstantT(final Type t) {
1144: return (null != t) && t.isAnnotated() && t.hasConstant(false);
1145: }
1146:
1147: public static boolean isConstructor(final Type declaringType,
1148: final MethodT maybeConstructor) {
1149: if (!declaringType.isClass())
1150: return false;
1151: return declaringType.toClass().getName().equals(
1152: maybeConstructor.getName());
1153: }
1154:
1155: /** ExpressionT > GeneralLValueT, GeneralRValueT. */
1156: public static boolean isExpressionT(final Type t) {
1157: return isGeneralLValueT(t) || isGeneralRValueT(t);
1158: }
1159:
1160: /** FieldT = Name WrappedRValueT. */
1161: public static boolean isFieldT(final Type t) {
1162: return t.isVariable()
1163: && VariableT.Kind.FIELD == t.toVariable().getKind();
1164: }
1165:
1166: /** GeneralLValueT > LValueT, VariableT, FieldT, ParameterT. */
1167: public static boolean isGeneralLValueT(final Type t) {
1168: return isLValueT(t) || isLocalT(t) || isFieldT(t)
1169: || isParameterT(t);
1170: }
1171:
1172: /** GeneralRValueT > NullT, WrappedRValueT. */
1173: public static boolean isGeneralRValueT(final Type t) {
1174: return isNullT(t) || isWrappedRValueT(t);
1175: }
1176:
1177: public static boolean isInLocalNameSpace(final String name) {
1178: final String lastPart = Utilities.unqualify(name);
1179: return SymbolTable.isInNameSpace(lastPart, "method")
1180: || SymbolTable.isInNameSpace(lastPart, "block")
1181: || SymbolTable.isInNameSpace(lastPart, "forStatement")
1182: || SymbolTable.isInNameSpace(lastPart,
1183: "labeledStatement")
1184: || SymbolTable.isInNameSpace(lastPart, "function") //in Jeannie, not in Java
1185: || SymbolTable.isInNameSpace(lastPart, "withStatement") //in Jeannie, not in Java
1186: || SymbolTable.isInNameSpace(lastPart, "matchClause") //in Matchete, not in Java
1187: || SymbolTable.isInNameSpace(lastPart, "catchClause");
1188: }
1189:
1190: public static boolean isInt(final Type t) {
1191: final Type n = JavaTypeConverter.promoteUnaryNumeric(t);
1192: if (null == n)
1193: return false;
1194: final Type r = resolveToRawRValue(n);
1195: return r.isInteger()
1196: && NumberT.Kind.INT == ((IntegerT) r).getKind();
1197: }
1198:
1199: /** LocalT = Name WrappedRValueT. */
1200: public static boolean isLocalT(final Type t) {
1201: return t.isVariable()
1202: && VariableT.Kind.LOCAL == t.toVariable().getKind();
1203: }
1204:
1205: /** LValueT = RValueT. */
1206: public static boolean isLValueT(final Type t) {
1207: return (null != t) && t.isAnnotated() && t.hasShape(false);
1208: }
1209:
1210: /** NotAValueT > PackageT, AnnotatedT:ReturnT --- annotated with Constants.ATT_NOT_A_VALUE */
1211: public static boolean isNotAValueT(final Type t) {
1212: return t.isPackage() || t instanceof AnnotatedT
1213: && t.hasAttribute(Constants.ATT_NOT_A_VALUE)
1214: && isReturnT(((AnnotatedT) t).getType());
1215: }
1216:
1217: /** NullT = ConstantT:VoidT. */
1218: public static boolean isNullT(final Type t) {
1219: return isConstantT(t) && ((AnnotatedT) t).getType().isVoid();
1220: }
1221:
1222: /** ParameterT = Name RValueT. */
1223: public static boolean isParameterT(final Type t) {
1224: return t.isVariable()
1225: && VariableT.Kind.PARAMETER == t.toVariable().getKind();
1226: }
1227:
1228: /** PrimitiveT > BooleanT, NumberT. */
1229: public static boolean isPrimitiveT(final Type t) {
1230: return t.isBoolean() || t.isNumber();
1231: }
1232:
1233: /** Is t a class, interface, or array type (gosling_et_al_2000 <a
1234: * href="http://java.sun.com/docs/books/jls/second_edition/html/typesValues.doc.html#9317">§4.3</a>)? */
1235: public static boolean isReferenceT(final Type t) {
1236: if (isNullT(t))
1237: return true;
1238: final Type u = isConstantT(t) ? ((AnnotatedT) t).getType() : t;
1239: return u.isArray() || isWrappedClassT(u)
1240: || isWrappedInterfaceT(u);
1241: }
1242:
1243: /** ReturnT > VoidT, RValueT. */
1244: public static boolean isReturnT(final Type t) {
1245: return t.isVoid() || isRValueT(t);
1246: }
1247:
1248: /** RValueT > PrimitiveT, ArrayT, WrappedClassT, WrappedInterfaceT. */
1249: public static boolean isRValueT(final Type t) {
1250: return isPrimitiveT(t) || t.isArray() || isWrappedClassT(t)
1251: || isWrappedInterfaceT(t);
1252: }
1253:
1254: public static boolean isScopeForMember(final String scopeName) {
1255: // gosling_et_al_2000 8.5, 9.5
1256: return isScopeNested(scopeName)
1257: && !isInLocalNameSpace(scopeName);
1258: }
1259:
1260: public static boolean isScopeLocal(final String scopeName) {
1261: //gosling_et_al_2000 14.3
1262: return isInLocalNameSpace(scopeName);
1263: }
1264:
1265: public static boolean isScopeNested(final String scopeName) {
1266: //gosling_et_al_2000 intro paragraph to chapters 8 and 9
1267: if (isScopeTopLevel(scopeName))
1268: return false;
1269: return 3 < Utilities.toComponents(scopeName).length;
1270: }
1271:
1272: public static boolean isScopeTopLevel(final String scopeName) {
1273: //gosling_et_al_2000 7.6
1274: if (null == scopeName)
1275: System.out.println("hohoho");
1276: assert null != scopeName;
1277: if ("".equals(scopeName) || ".".equals(scopeName))
1278: return true; //top-level in C file
1279: final String[] scopeParts = Utilities.toComponents(scopeName);
1280: if (0 < scopeParts.length)
1281: assert "".equals(scopeParts[0]);
1282: if (2 < scopeParts.length
1283: && SymbolTable.isInNameSpace(scopeParts[1], "package")) {
1284: assert SymbolTable.isInNameSpace(scopeParts[2], "file");
1285: return 3 == scopeParts.length; //top-level in Java file
1286: }
1287: return false;
1288: }
1289:
1290: public static boolean isSuperClass(final SymbolTable tab,
1291: final List<File> paths, final Type sup, final Type sub) {
1292: if (!isWrappedClassT(sub) || !isWrappedClassT(sup))
1293: return false;
1294: return JavaTypeConverter.isIdentical(sup, sub)
1295: || JavaTypeConverter.isWiderReference(tab, paths, sup,
1296: sub);
1297: }
1298:
1299: /** Note: not symmetric! */
1300: public static boolean isSuperMethod(final SymbolTable tab,
1301: final List<File> paths, final MethodT sup, final MethodT sub) {
1302: if (!sub.getName().equals(sup.getName()))
1303: return false;
1304: if (sub.getParameters().size() != sup.getParameters().size())
1305: return false;
1306: if (hasModifier(sup, "private"))
1307: return false;
1308: final ClassOrInterfaceT dSup = declaringType(tab, sup), dSub = declaringType(
1309: tab, sub);
1310: if (!isAccessibleFromIn(tab, paths, typeToScopeName(dSub), sup,
1311: dSup))
1312: return false;
1313: if (!JavaTypeConverter.isParameterPassable(tab, paths, dSup,
1314: dSub))
1315: return false;
1316: final Iterator<Type> iSub = sub.getParameters().iterator();
1317: final Iterator<Type> iSup = sup.getParameters().iterator();
1318: while (iSub.hasNext()) {
1319: final VariableT tSup = iSup.next().toVariable(), tSub = iSub
1320: .next().toVariable();
1321: final Type rSup = tSup.getType(), rSub = tSub.getType();
1322: resolveIfAlias(tab, paths, declaringScopeName(sup), rSup);
1323: resolveIfAlias(tab, paths, declaringScopeName(sub), rSub);
1324: if (!JavaTypeConverter.isParameterPassable(tab, paths,
1325: rSup, rSub))
1326: return false;
1327: }
1328: if (JavaTypeConverter.isIdentical(dSup, dSub)
1329: && sameMethodSignature(sup, sub)) {
1330: //Java 1.5 introduces contravariant return types, and we must tackle them in libraries, such as StringBuffer
1331: final Type tSup = sup.getResult(), tSub = sub.getResult();
1332: resolveIfAlias(tab, paths, declaringScopeName(sup), tSup);
1333: resolveIfAlias(tab, paths, declaringScopeName(sub), tSub);
1334: if (!JavaTypeConverter.isReturnTypeSubstitutable(tab,
1335: paths, tSup, tSub))
1336: return false;
1337: }
1338: return true;
1339: }
1340:
1341: public static boolean isTypeAnonymous(final ClassOrInterfaceT t) {
1342: return t.isClass() && null == t.toClass().getName();
1343: }
1344:
1345: public static boolean isTypeInner(final ClassOrInterfaceT t) {
1346: // gosling_et_al_2000 8.1.2
1347: return !hasModifier(t, "static") && isTypeNested(t);
1348: }
1349:
1350: public static boolean isTypeLocal(final ClassOrInterfaceT t) {
1351: // gosling_et_al_2000 14.3
1352: return isScopeLocal(declaringScopeName(t))
1353: && !isTypeAnonymous(t);
1354: }
1355:
1356: public static boolean isTypeMember(final Type t) {
1357: return isScopeForMember(declaringScopeName(t));
1358: }
1359:
1360: public static boolean isTypeNamed(final ClassOrInterfaceT t) {
1361: return !isTypeAnonymous(t);
1362: }
1363:
1364: public static boolean isTypeNested(final ClassOrInterfaceT t) {
1365: final String scope = declaringScopeName(t);
1366: assert null != scope;
1367: return isScopeNested(scope);
1368: }
1369:
1370: public static boolean isTypeTopLevel(final ClassOrInterfaceT t) {
1371: return isScopeTopLevel(declaringScopeName(t));
1372: }
1373:
1374: /** WrappedClassT = AliasT:Name / AliasT:ResolvedClassT / ResolvedClassT. */
1375: public static boolean isWrappedClassT(final Type t) {
1376: if (t.isAlias()) {
1377: final Type r = ((AliasT) t).getType();
1378: return null == r || r.isClass();
1379: }
1380: return t.isClass();
1381: }
1382:
1383: /** WrappedInterfaceT = AliasT:Name / AliasT:ResolvedInterfaceT / ResolvedInterfaceT. */
1384: public static boolean isWrappedInterfaceT(final Type t) {
1385: if (t.isAlias()) {
1386: final Type r = ((AliasT) t).getType();
1387: return null == r || r.isInterface();
1388: }
1389: return t.isInterface();
1390: }
1391:
1392: /** WrappedRValueT = ConstantT:RValueT / RValueT. */
1393: public static boolean isWrappedRValueT(final Type t) {
1394: return isConstantT(t) && isRValueT(((AnnotatedT) t).getType())
1395: || isRValueT(t);
1396: }
1397:
1398: public static String javaAstToString(final Node ast) {
1399: final CharArrayWriter writer = new CharArrayWriter();
1400: final JavaPrinter printer = new JavaPrinter(new Printer(writer));
1401: printer.dispatch(ast);
1402: return writer.toString();
1403: }
1404:
1405: /**
1406: * Don't use this method gratuitously. Originally, I used this to serialize
1407: * ASTs into strings, then concatenated the strings into more code, then
1408: * reparsed the result to a larger AST. But that is slow and less elegant
1409: * than using FactoryFactory.
1410: */
1411: private static GNode javaStringToAst(final String production,
1412: final String code) {
1413: try {
1414: return JavaEntities.javaStringToAst(production, code, true);
1415: } catch (final Exception e) {
1416: throw new Error(e);
1417: }
1418: }
1419:
1420: public static GNode javaStringToAst(final String production,
1421: final String escaped, final boolean simple)
1422: throws Exception {
1423: final Method method = JavaParser.class.getDeclaredMethod("p"
1424: + production, Integer.TYPE);
1425: method.setAccessible(true);
1426: final String string = unicodeUnescape(escaped);
1427: final JavaParser parser = new JavaParser( //
1428: new StringReader(string), "<input>", string.length());
1429: final Object[] paramValues = { new Integer(0) };
1430: final Result parseResult = (Result) method.invoke(parser,
1431: paramValues);
1432: if (!parseResult.hasValue())
1433: parser.signal(parseResult.parseError());
1434: if (parseResult.index != string.length())
1435: throw new ParseException("input not fully consumed");
1436: final GNode ast = (GNode) parseResult.semanticValue();
1437: if (simple)
1438: return (GNode) new JavaAstSimplifier().dispatch(ast);
1439: return ast;
1440: }
1441:
1442: public static Type javaStringToType(final String code) {
1443: final SymbolTable tab = new SymbolTable();
1444: JavaUnitTests.enterPackageFile(tab, "", "<input>");
1445: return javaStringToType(code, tab);
1446: }
1447:
1448: private static Type javaStringToType(final String code,
1449: final SymbolTable tab) {
1450: final GNode ast = JavaEntities.javaStringToAst("Type", code);
1451: final JavaAnalyzer ana = new JavaAnalyzer(JavaUnitTests
1452: .newRuntime(), tab);
1453: final Type result = (Type) ana.dispatch(ast);
1454: return result;
1455: }
1456:
1457: public static GNode javaTypeToAst(final SymbolTable tab,
1458: final Type type) {
1459: final String s = JavaEntities.javaTypeToString(tab, type);
1460: final GNode result = JavaEntities.javaStringToAst("ResultType",
1461: s);
1462: return scrubLocations(result);
1463: }
1464:
1465: public static String javaTypeToString(final SymbolTable tab,
1466: final Type type) {
1467: if (JavaEntities.isGeneralRValueT(type)) {
1468: final Type r = JavaEntities.resolveToRawRValue(type);
1469: return JavaEntities.typeToString(tab, false, r);
1470: }
1471: return JavaEntities.typeToString(tab, false, type);
1472: }
1473:
1474: /**
1475: * Resolve single-type import. The name is canonical (gosling_et_al_2000
1476: * Section 7.5.1) and denotes a class or interface. The only thing that is
1477: * uncertain is where the package ends and where the nested types start. For
1478: * example, in a.b.c, it could be that the package is a.b and the class is c,
1479: * or that the package is a, the outer class is b, and the inner class is c.
1480: * There can be no ambiguity (gosling_et_al_2000 Section 6.4), because a
1481: * package must not have a top-level type and a subpackage of the same name.
1482: */
1483: static ClassOrInterfaceT lookupImport(final SymbolTable tab,
1484: final List<File> paths, final AliasT alias) {
1485: return canonicalAliasToType(tab, paths, alias, false);
1486: }
1487:
1488: public static List<Type> memberTypesApplicableAndAccessible(
1489: final SymbolTable tab, final List<File> paths,
1490: final ClassOrInterfaceT base, final boolean parents,
1491: final String name) {
1492: final List<Type> memberTypes = parents ? memberTypesOwnAndInherited(
1493: tab, paths, base)
1494: : memberTypesOwn(tab, paths, base);
1495: final List<Type> result = new ArrayList<Type>();
1496: for (final Type memberType : memberTypes)
1497: if (isAccessibleIn(tab, paths, memberType, base))
1498: if (isApplicableMemberType(memberType, name))
1499: result.add(memberType);
1500: return result;
1501: }
1502:
1503: public static List<Type> memberTypesInherited(
1504: final SymbolTable tab, final List<File> paths,
1505: final ClassOrInterfaceT base) {
1506: //gosling_et_al_2000 8.5 (before subsections)
1507: final List<Type> result = new ArrayList<Type>();
1508: final List<Type> memberTypesOwn = memberTypesOwn(tab, paths,
1509: base);
1510: final String baseScope = declaringScopeName(base);
1511: assert null != baseScope || base.isArray();
1512: final List<ClassOrInterfaceT> super Types = directSuperTypes(
1513: tab, paths, base);
1514: for (final ClassOrInterfaceT super Type : super Types) {
1515: final List<Type> super MemberTypes = memberTypesOwnAndInherited(
1516: tab, paths, super Type);
1517: super MemberTypes: for (final Type t : super MemberTypes) {
1518: //the private and accessible checks are here for consistency with fieldsInherited, the specification doesn't explicitly mention them
1519: if (hasModifier(t, "private"))
1520: continue super MemberTypes;
1521: if (null != baseScope
1522: && !isAccessibleFromIn(tab, paths, baseScope,
1523: t, super Type))
1524: continue super MemberTypes;
1525: final String tName = resolveToRawClassOrInterfaceT(t)
1526: .getName();
1527: for (final Type o : memberTypesOwn)
1528: if (tName.equals(resolveToRawClassOrInterfaceT(o)
1529: .getName()))
1530: continue super MemberTypes;
1531: for (final Type r : result)
1532: if (t == r)
1533: continue super MemberTypes;
1534: result.add(t);
1535: }
1536: }
1537: return result;
1538: }
1539:
1540: public static List<Type> memberTypesOwn(final SymbolTable tab,
1541: final List<File> paths, final ClassOrInterfaceT base) {
1542: if (base.isArray())
1543: return new ArrayList<Type>(0);
1544: final Scope scope = tab.getScope(typeToScopeName(base));
1545: final List<Type> result = new ArrayList<Type>();
1546: for (final Iterator<String> i = scope.symbols(); i.hasNext();) {
1547: final String symbol = i.next();
1548: final Type member = (Type) scope.lookupLocally(symbol);
1549: if (isWrappedClassT(member) || isWrappedInterfaceT(member))
1550: result.add(member);
1551: }
1552: return result;
1553: }
1554:
1555: public static List<Type> memberTypesOwnAndInherited(
1556: final SymbolTable tab, final List<File> paths,
1557: final ClassOrInterfaceT base) {
1558: final List<Type> result = new ArrayList<Type>();
1559: result.addAll(memberTypesInherited(tab, paths, base));
1560: result.addAll(memberTypesOwn(tab, paths, base));
1561: return result;
1562: }
1563:
1564: /** All methods in the base type that are accessible, and whose formals accept the actuals
1565: * after method invocation conversion (gosling_et_al_2000 <a
1566: * href="http://java.sun.com/docs/books/jls/second_edition/html/expressions.doc.html#18427">§15.12.2.1</a>). */
1567: public static List<MethodT> methodsApplicableAndAccessible(
1568: final SymbolTable tab, final List<File> paths,
1569: final Type base, final boolean parents, final String name,
1570: final List<Type> actuals) {
1571: final List<MethodT> methods = parents ? methodsOwnAndInherited(
1572: tab, paths, base) : methodsOwn(base);
1573: final List<MethodT> result = new ArrayList<MethodT>();
1574: for (final MethodT method : methods)
1575: if (isAccessibleIn(tab, paths, method, base))
1576: if (isApplicableMethod(tab, paths, method, name,
1577: actuals))
1578: result.add(method);
1579: return result;
1580: }
1581:
1582: public static List<MethodT> methodsInherited(final SymbolTable tab,
1583: final List<File> paths, final Type base,
1584: final boolean includeOverridden) {
1585: //gosling_et_al_2000 8.4.6
1586: List<MethodT> result = new ArrayList<MethodT>();
1587: final List<MethodT> methodsOwn = methodsOwn(base);
1588: final String baseScope = typeToScopeName(base); //declaringScopeName(base);
1589: assert null != baseScope || base.isArray();
1590: final List<ClassOrInterfaceT> super Types = directSuperTypes(
1591: tab, paths, base);
1592: for (final ClassOrInterfaceT super Type : super Types) {
1593: final List<MethodT> super Methods = methodsOwnAndInherited(
1594: tab, paths, super Type);
1595: super Methods: for (final MethodT m : super Methods) {
1596: resolveIfAliasMethod(tab, paths, m);
1597: if (hasModifier(m, "private"))
1598: continue super Methods;
1599: if (null != baseScope
1600: && !isAccessibleFromIn(tab, paths, baseScope,
1601: m, super Type))
1602: continue super Methods;
1603: if (!includeOverridden)
1604: for (final MethodT o : methodsOwn) {
1605: resolveIfAliasMethod(tab, paths, o);
1606: if (sameMethodSignature(o, m))
1607: continue super Methods;
1608: }
1609: boolean mustRemoveDuplicates = false;
1610: for (final MethodT r : result) {
1611: if (r == m)
1612: continue super Methods; //inherited from same interface by two different paths
1613: if (sameMethodSignature(m, r)) {
1614: assert hasModifier(m, "abstract")
1615: || hasModifier(r, "abstract");
1616: if (hasModifier(m, "abstract")
1617: && hasModifier(r, "abstract")) {
1618: //TD 39 (8.4.6) report error if incompatible return types
1619: } else if (!hasModifier(m, "abstract")) {
1620: mustRemoveDuplicates = true;
1621: } else if (!hasModifier(r, "abstract")) {
1622: //TD 39 (8.4.6) report error if r is static
1623: continue super Methods;
1624: }
1625: }
1626: }
1627: result.add(m);
1628: if (mustRemoveDuplicates) {
1629: //TD 39 (8.4.6) report error if m is static
1630: final List<MethodT> oldResult = result;
1631: result = new ArrayList<MethodT>();
1632: for (final MethodT r : oldResult)
1633: if (r == m || !sameMethodSignature(r, m))
1634: result.add(r);
1635: }
1636: }
1637: }
1638: return result;
1639: }
1640:
1641: public static List<MethodT> methodsOwn(final Type base) {
1642: final List<MethodT> result = new ArrayList<MethodT>();
1643: if (!base.isArray()) //TD should methodsOwn() list of array type be non-empty?
1644: for (final Type m : resolveToRawClassOrInterfaceT(base)
1645: .getMethods())
1646: result.add(m.toMethod());
1647: return result;
1648: }
1649:
1650: public static List<MethodT> methodsOwnAndInherited(
1651: final SymbolTable tab, final List<File> paths,
1652: final Type base) {
1653: final List<MethodT> result = new ArrayList<MethodT>();
1654: result.addAll(methodsInherited(tab, paths, base, false));
1655: result.addAll(methodsOwn(base));
1656: return result;
1657: }
1658:
1659: public static String methodSymbolFromAst(final GNode ast) {
1660: final String name = ast.getString(3);
1661: final String args = javaAstToString(ast.getGeneric(4));
1662: /* In general, the arguments are unresolved, hence the scope name
1663: * is not canonical, hence it is useless for future lookup. That
1664: * is fine as long as we never look up methods or their scopes by
1665: * name. Instead, we should rely on the SCOPE attribute for that. */
1666: return "method(" + name + ")" + args;
1667: }
1668:
1669: public static String methodSymbolFromConstructor(
1670: final Constructor method) {
1671: final StringBuilder result = new StringBuilder();
1672: result.append("method(<init>)");
1673: methodSymbolHelper(result, method.getParameterTypes());
1674: return result.toString();
1675: }
1676:
1677: public static String methodSymbolFromMethod(final Method method) {
1678: final StringBuilder result = new StringBuilder();
1679: result.append("method(").append(method.getName()).append(")");
1680: methodSymbolHelper(result, method.getParameterTypes());
1681: return result.toString();
1682: }
1683:
1684: private static void methodSymbolHelper(final StringBuilder b,
1685: final Class[] t) {
1686: b.append('(');
1687: for (int i = 0; i < t.length; i++) {
1688: if (0 < i)
1689: b.append(',');
1690: b.append(t[i].getName());
1691: }
1692: b.append(')');
1693: }
1694:
1695: public static String modifiersToString(final Type type) {
1696: final StringBuilder result = new StringBuilder();
1697: for (final Attribute att : type.attributes()) {
1698: if (0 < result.length())
1699: result.append(' ');
1700: result.append(modifierToName(att));
1701: }
1702: return result.toString();
1703: }
1704:
1705: public static String modifierToName(final Attribute modifier) {
1706: return MODIFIER_TO_NAME.get(modifier);
1707: }
1708:
1709: private static List<MethodT> mostSpecificMethods(
1710: final SymbolTable tab, final List<File> paths,
1711: final List<MethodT> allMethods) {
1712: final List<MethodT> result = new ArrayList<MethodT>();
1713: outer: for (final MethodT mOuter : allMethods) {
1714: for (final MethodT mInner : allMethods)
1715: if (mOuter != mInner
1716: && isSuperMethod(tab, paths, mOuter, mInner))
1717: continue outer;
1718: result.add(mOuter);
1719: }
1720: return result;
1721: }
1722:
1723: public static Type nameToBaseType(final String name) {
1724: return NAME_TO_BASETYPE.get(name);
1725: }
1726:
1727: public static Attribute nameToModifier(final String name) {
1728: final Attribute result = NAME_TO_MODIFIER.get(name);
1729: assert null != result;
1730: return result;
1731: }
1732:
1733: public static MethodT newRawConstructor(final Type base,
1734: final List<Type> formals, final List<Type> exceptions) {
1735: return new MethodT(
1736: constructorsReturnVoid() ? nameToBaseType("void")
1737: : base, typeToSimpleName(base), formals, false,
1738: exceptions);
1739: }
1740:
1741: public static Type notAValueIfClassOrInterface(final Type t) {
1742: if (null == t)
1743: return t;
1744: if (isWrappedClassT(t) || isWrappedInterfaceT(t)) {
1745: final Type result = new AnnotatedT(t);
1746: /* don't call t.attribute(), because that would pollute aliases of t */
1747: return result.attribute(Constants.ATT_NOT_A_VALUE);
1748: }
1749: return t;
1750: }
1751:
1752: public static PackageT packageDotPackage(final SymbolTable tab,
1753: final PackageT base, final String selector) {
1754: final String tagName = SymbolTable.toTagName(selector);
1755: final String scopeName = packageNameToScopeName(base.getName());
1756: final String symbol = "."
1757: + Utilities.qualify(scopeName, tagName);
1758: PackageT result = (PackageT) tab.lookup(symbol);
1759: if (result == null) {
1760: result = new PackageT(Utilities.qualify(base.getName(),
1761: selector));
1762: SymbolTable.Scope scope = tab.lookupScope(symbol);
1763: if (scope == null) {
1764: final SymbolTable.Scope oldScope = tab.current();
1765: tab.setScope(tab.root());
1766: tab.enter(packageNameToScopeName(base.getName()));
1767: scope = tab.current();
1768: tab.setScope(oldScope);
1769: }
1770: scope.define(tagName, result);
1771: }
1772: return result;
1773: }
1774:
1775: public static Type packageDotPackageOrType(final SymbolTable tab,
1776: final List<File> paths, final PackageT base,
1777: final String selector) {
1778: final Type t = packageDotType(tab, paths, base, selector);
1779: return t != null ? t : packageDotPackage(tab, base, selector);
1780: }
1781:
1782: static ClassOrInterfaceT packageDotType(final SymbolTable tab,
1783: final List<File> paths, final PackageT base,
1784: final String selector) {
1785: assert null != base;
1786: final ClassOrInterfaceT t1 = packageDotType_existing(tab, base,
1787: selector);
1788: if (null != t1)
1789: return t1;
1790: final ClassOrInterfaceT t2 = packageDotType_external(tab,
1791: paths, base, selector);
1792: if (null != t2)
1793: return t2;
1794: return packageDotType_noSource(tab, base, selector);
1795: }
1796:
1797: private static ClassOrInterfaceT packageDotType_existing(
1798: final SymbolTable tab, final PackageT base,
1799: final String selector) {
1800: final String tagName = SymbolTable.toTagName(selector);
1801: final String baseScopeName = "."
1802: + packageNameToScopeName(base.getName());
1803: final SymbolTable.Scope scope = tab.getScope(baseScopeName);
1804: if (scope != null)
1805: for (final Iterator<String> i = scope.nested(); i.hasNext();) {
1806: final String symbol = baseScopeName + "." + i.next()
1807: + "." + tagName;
1808: final Type result = (Type) tab.lookup(symbol);
1809: if (result != null && !result.isAlias())
1810: return (ClassOrInterfaceT) result;
1811: }
1812: return null;
1813: }
1814:
1815: private static ClassOrInterfaceT packageDotType_external(
1816: final SymbolTable tab, final List<File> paths,
1817: final PackageT base, final String selector) {
1818: final String tagName = SymbolTable.toTagName(selector);
1819: final String suffix = File.separatorChar
1820: + Utilities.toPath(base.getName()) + File.separatorChar
1821: + selector + ".java";
1822: for (final File prefix : paths) {
1823: try {
1824: final File file = new File(prefix, suffix);
1825: final String path = file.getAbsolutePath();
1826: if (file.exists()) {
1827: final String scopedName = scopeName(base, path)
1828: + "." + tagName;
1829: if (null == tab.lookupScope(scopedName)) {
1830: final String oldScope = enterScopeByQualifiedName(
1831: tab, "");
1832: FileReader fileReader = null;
1833: try {
1834: fileReader = new FileReader(file);
1835: final UnicodeUnescaper unescaper = new UnicodeUnescaper(
1836: fileReader);
1837: final JavaParser parser = new JavaParser(
1838: unescaper, path);
1839: final Result parseResult = parser
1840: .pCompilationUnit(0);
1841: if (parseResult.hasValue()) {
1842: final GNode ast = (GNode) parseResult
1843: .semanticValue();
1844: final GNode simple = (GNode) new JavaAstSimplifier()
1845: .dispatch(ast);
1846: new JavaExternalAnalyzer(new Runtime(),
1847: tab).dispatch(simple);
1848: }
1849: } finally {
1850: if (null != fileReader)
1851: fileReader.close();
1852: }
1853: enterScopeByQualifiedName(tab, oldScope);
1854: }
1855: final ClassOrInterfaceT result = (ClassOrInterfaceT) tab
1856: .lookup(scopedName);
1857: if (result != null)
1858: return result;
1859: }
1860: } catch (final IOException e) {
1861: e.printStackTrace();
1862: }
1863: }
1864: return null;
1865: }
1866:
1867: static ClassOrInterfaceT packageDotType_noSource(
1868: final SymbolTable tab, final PackageT base,
1869: final String selector) {
1870: final String scopedName = "."
1871: + packageNameToScopeName(base.getName()) + ".file()."
1872: + SymbolTable.toTagName(selector);
1873: if (null == tab.lookup(scopedName)) {
1874: final Class clazz;
1875: try {
1876: clazz = Class.forName(base.getName() + "." + selector);
1877: } catch (final ClassNotFoundException e) {
1878: return null;
1879: }
1880: if (base.getName().equals(clazz.getPackage().getName())) {
1881: final String oldScope = enterScopeByQualifiedName(tab,
1882: "");
1883: tab.enter(packageNameToScopeName(base.getName()));
1884: tab.enter("file()");
1885: new JavaNoSourceAnalyzer(tab)
1886: .visitClassOrInterface(clazz);
1887: enterScopeByQualifiedName(tab, oldScope);
1888: }
1889: }
1890: return (ClassOrInterfaceT) tab.lookup(scopedName);
1891: }
1892:
1893: public static String packageNameToScopeName(
1894: final String canonicalName) {
1895: return SymbolTable.toNameSpace(canonicalName, "package");
1896: }
1897:
1898: public static String qNameWithDollars(final SymbolTable tab,
1899: final ClassOrInterfaceT t) {
1900: final String allDots = t.getQName();
1901: if (null == tab)
1902: return allDots;
1903: final String packageName = declaringPackage(tab, t).getName();
1904: if (0 == packageName.length())
1905: return allDots;
1906: assert allDots.startsWith(packageName);
1907: final String afterPackage = allDots.substring(
1908: packageName.length() + 1).replace('.', '$');
1909: final String result = packageName + "." + afterPackage;
1910: return result;
1911: }
1912:
1913: public static List<ClassOrInterfaceT> qualifiedAliasesToTypes(
1914: final SymbolTable tab, final List<File> paths,
1915: final String scope, final List<AliasT> aliases) {
1916: final List<ClassOrInterfaceT> result = new ArrayList<ClassOrInterfaceT>(
1917: aliases.size());
1918: for (final AliasT a : aliases) {
1919: final ClassOrInterfaceT resolved = JavaEntities
1920: .qualifiedAliasToType(tab, paths, scope, a);
1921: if (null != resolved)
1922: result.add(resolved);
1923: }
1924: return result;
1925: }
1926:
1927: public static ClassOrInterfaceT qualifiedAliasToType(
1928: final SymbolTable tab, final List<File> paths,
1929: final String scope, final AliasT alias) {
1930: if (alias.getType() == null)
1931: alias.setType(qualifiedNameToType(tab, paths, scope, alias
1932: .getName()));
1933: return (ClassOrInterfaceT) alias.getType();
1934: }
1935:
1936: public static Type qualifiedNameToPackageOrType(
1937: final SymbolTable tab, final List<File> paths,
1938: final String scope, final String name) {
1939: final Type t = qualifiedNameToType(tab, paths, scope, name);
1940: return t != null ? t : canonicalNameToPackage(tab, name);
1941: }
1942:
1943: public static ClassOrInterfaceT qualifiedNameToType(
1944: final SymbolTable tab, final List<File> paths,
1945: final String scope, final String name) {
1946: if (name.indexOf('.') == -1)
1947: return simpleNameToType(tab, paths, scope, name);
1948: final String qualifier = Utilities.getQualifier(name);
1949: final String selector = Utilities.unqualify(name);
1950: final Type base = qualifiedNameToPackageOrType(tab, paths,
1951: scope, qualifier);
1952: if (base.isPackage())
1953: return packageDotType(tab, paths, base.toPackage(),
1954: selector);
1955: return typeDotType(tab, paths, (ClassOrInterfaceT) base, true,
1956: selector);
1957: }
1958:
1959: public static Type resolveIfAlias(final SymbolTable tab,
1960: final List<File> paths, final String scope,
1961: final Type typeThatMayBeAlias) {
1962: assert null != scope;
1963: if (null == typeThatMayBeAlias)
1964: return null;
1965: if (isGeneralLValueT(typeThatMayBeAlias)) {
1966: final Type t = dereference(typeThatMayBeAlias);
1967: resolveIfAlias(tab, paths, scope, t);
1968: return typeThatMayBeAlias;
1969: }
1970: if (typeThatMayBeAlias.isAnnotated()) {
1971: final Type t = ((AnnotatedT) typeThatMayBeAlias).getType();
1972: resolveIfAlias(tab, paths, scope, t);
1973: return typeThatMayBeAlias;
1974: }
1975: if (typeThatMayBeAlias.isArray()) {
1976: final Type t = arrayElementType(typeThatMayBeAlias
1977: .toArray());
1978: resolveIfAlias(tab, paths, scope, t);
1979: return typeThatMayBeAlias;
1980: }
1981: if (typeThatMayBeAlias.isAlias())
1982: return qualifiedAliasToType(tab, paths, scope,
1983: typeThatMayBeAlias.toAlias());
1984: return typeThatMayBeAlias;
1985: }
1986:
1987: public static MethodT resolveIfAliasMethod(final SymbolTable tab,
1988: final List<File> paths, final MethodT method) {
1989: final String scope = declaringScopeName(method);
1990: assert null != scope;
1991: resolveIfAlias(tab, paths, scope, declaringType(tab, method));
1992: resolveIfAlias(tab, paths, scope, method.getResult());
1993: for (final Type p : method.getParameters())
1994: resolveIfAlias(tab, paths, scope, p);
1995: for (final Type e : method.getExceptions())
1996: resolveIfAlias(tab, paths, scope, e);
1997: return method;
1998: }
1999:
2000: static ClassOrInterfaceT resolveToRawClassOrInterfaceT(final Type t) {
2001: return (ClassOrInterfaceT) resolveToRawRValue(t);
2002: }
2003:
2004: public static WrappedT resolveToRawLValue(final Type t) {
2005: assert isGeneralLValueT(t);
2006: final boolean a = t.isAnnotated();
2007: final WrappedT r = (WrappedT) (a ? ((AnnotatedT) t).getType()
2008: : t);
2009: assert isLValueT(r) || isLocalT(r) || isFieldT(r)
2010: || isParameterT(r);
2011: return r;
2012: }
2013:
2014: public static Type resolveToRawRValue(final Type t) {
2015: assert isGeneralRValueT(t);
2016: Type result = t;
2017: if (!isNullT(result))
2018: while (true) {
2019: if (result.isAlias())
2020: result = ((AliasT) result).getType();
2021: else if (result.isAnnotated())
2022: result = ((AnnotatedT) result).getType();
2023: else if (isConstantT(result))
2024: result = ((AnnotatedT) result).getType();
2025: else
2026: break;
2027: }
2028: assert isNullT(result) || isPrimitiveT(result)
2029: || result.isArray() || result.isClass()
2030: || result.isInterface();
2031: return result;
2032: }
2033:
2034: public static Type resolveToRValue(final Type t0) {
2035: assert isGeneralRValueT(t0);
2036: final Type t1 = isConstantT(t0) ? ((AnnotatedT) t0).getType()
2037: : t0;
2038: final Type t2 = t1.isAlias() ? ((AliasT) t1).getType() : t1;
2039: assert isPrimitiveT(t2) || t2.isArray() || t2.isClass()
2040: || t2.isInterface();
2041: return t2;
2042: }
2043:
2044: public static Type resolveToValue(final AnnotatedT notAValue) {
2045: assert isNotAValueT(notAValue);
2046: Type result = notAValue.getType();
2047: for (final Attribute a : notAValue.attributes()) {
2048: if (!a.equals(Constants.ATT_NOT_A_VALUE))
2049: result = result.attribute(a);
2050: }
2051: if (notAValue.hasScope(false))
2052: result.scope(notAValue.getScope());
2053: return result;
2054: }
2055:
2056: public static boolean runtimeAssrt(final Runtime runtime,
2057: final Node n, final boolean cond, final String msgFormat,
2058: final Object... msgArgs) {
2059: if (!cond) {
2060: final Formatter message = new Formatter();
2061: message.format(msgFormat, msgArgs);
2062: runtime.error(message.toString(), n);
2063: }
2064: return cond;
2065: }
2066:
2067: public static boolean sameMethodReturnType(final MethodT m1,
2068: final MethodT m2) {
2069: final Type r1 = m1.getResult(), r2 = m2.getResult();
2070: if (r1.isVoid() || r2.isVoid())
2071: return r1.isVoid() && r2.isVoid();
2072: return JavaTypeConverter.isIdentical(r1, r2);
2073: }
2074:
2075: public static boolean sameMethodSignature(final MethodT m1,
2076: final MethodT m2) {
2077: if (!m1.getName().equals(m2.getName()))
2078: return false;
2079: final List<Type> params1 = m1.getParameters(), params2 = m2
2080: .getParameters();
2081: if (params1.size() != params2.size())
2082: return false;
2083: final Iterator<Type> i1 = params1.iterator(), i2 = params2
2084: .iterator();
2085: while (i1.hasNext()) {
2086: final Type t1 = i1.next(), t2 = i2.next();
2087: assert isParameterT(t1) && isParameterT(t2);
2088: final Type r1 = dereference(t1), r2 = dereference(t2);
2089: if (!JavaTypeConverter.isIdentical(r1, r2))
2090: return false;
2091: }
2092: return true;
2093: }
2094:
2095: static String scopeName(final PackageT packageT,
2096: final String fileName) {
2097: return "." + packageNameToScopeName(packageT.getName()) + "."
2098: + fileNameToScopeName(fileName);
2099: }
2100:
2101: public static GNode scrubLocations(final GNode result) {
2102: new MiniVisitor_scrubLocations().dispatch(result);
2103: return result;
2104: }
2105:
2106: public static Type simpleNameToExpression(final SymbolTable tab,
2107: final List<File> paths, final String scope,
2108: final String name) {
2109: final String oldScope = enterScopeByQualifiedName(tab, scope);
2110: final Type result = (Type) tab.lookup(name);
2111: resolveIfAlias(tab, paths, scope, result);
2112: final boolean found = null != result
2113: && isGeneralLValueT(result);
2114: if (found) {
2115: final Type rValue = dereference(result);
2116: resolveIfAlias(tab, paths,
2117: typeToScopeName(currentType(tab)), rValue);
2118: }
2119: enterScopeByQualifiedName(tab, oldScope);
2120: if (!found && isScopeNested(tab.current().getQualifiedName()))
2121: return typeDotField(tab, paths, currentType(tab), true,
2122: name);
2123: return result;
2124: }
2125:
2126: public static PackageT simpleNameToPackage(final SymbolTable tab,
2127: final String name) {
2128: final String tagName = SymbolTable.toTagName(name);
2129: final String toplevelScopeDotSymbol = "." + tagName;
2130: PackageT result = (PackageT) tab.lookup(toplevelScopeDotSymbol);
2131: if (result == null) {
2132: result = new PackageT(name);
2133: tab.lookupScope(toplevelScopeDotSymbol).define(tagName,
2134: result);
2135: }
2136: return result;
2137: }
2138:
2139: public static Type simpleNameToPackageOrType(final SymbolTable tab,
2140: final List<File> paths, final String scope,
2141: final String name) {
2142: final Type t = simpleNameToType(tab, paths, scope, name);
2143: return t != null ? t : simpleNameToPackage(tab, name);
2144: }
2145:
2146: public static Type simpleNameToPackageOrTypeOrExpression(
2147: final SymbolTable tab, final List<File> paths,
2148: final String scope, final String name) {
2149: final Type e = simpleNameToExpression(tab, paths, scope, name);
2150: return e != null ? e : simpleNameToPackageOrType(tab, paths,
2151: scope, name);
2152: }
2153:
2154: public static ClassOrInterfaceT simpleNameToType(
2155: final SymbolTable tab, final List<File> paths,
2156: final String scope, final String name) {
2157: final String oldScope = enterScopeByQualifiedName(tab, scope);
2158: ClassOrInterfaceT result = null;
2159: { // find as local class, member class, single-import, or top-level class
2160: final Type t = (Type) tab.lookup(SymbolTable
2161: .toTagName(name));
2162: if (null != t && !t.isPackage())
2163: result = t.isAlias() ? lookupImport(tab, paths, t
2164: .toAlias()) : (ClassOrInterfaceT) t;
2165: }
2166: if (null == result && isScopeNested(scope))
2167: result = typeDotType(tab, paths, currentType(tab), true,
2168: name);
2169: if (null == result)
2170: // find in other compilation unit of current package
2171: result = packageDotType(tab, paths, currentPackage(tab),
2172: name);
2173: if (null == result) {
2174: final List<Type> imports = currentImports(tab);
2175: if (null != imports)
2176: // find in import-on-demand
2177: for (final Type i : imports) {
2178: result = packageDotType(tab, paths, (PackageT) i,
2179: name);
2180: if (null != result)
2181: break;
2182: }
2183: }
2184: if (null == result)
2185: result = packageDotType(tab, paths, canonicalNameToPackage(
2186: tab, "java.lang"), name);
2187: enterScopeByQualifiedName(tab, oldScope);
2188: if (null == result)
2189: return null;
2190: return result;
2191: }
2192:
2193: @SuppressWarnings("unchecked")
2194: public static Set<String> stringSet(final Object s) {
2195: return (Set<String>) s;
2196: }
2197:
2198: public static ClassT tClass(final SymbolTable tab) {
2199: return tForName(tab, "java.lang.Class").toClass();
2200: }
2201:
2202: public static InterfaceT tCloneable(final SymbolTable tab) {
2203: return tForName(tab, "java.lang.Cloneable").toInterface();
2204: }
2205:
2206: public static ClassT tError(final SymbolTable tab) {
2207: return tForName(tab, "java.lang.Error").toClass();
2208: }
2209:
2210: private static ClassOrInterfaceT tForName(final SymbolTable tab,
2211: final String name) {
2212: final List<File> paths = new ArrayList<File>();
2213: return canonicalNameToType(tab, paths, name, false);
2214: }
2215:
2216: public static ClassT tObject(final SymbolTable tab) {
2217: return tForName(tab, "java.lang.Object").toClass();
2218: }
2219:
2220: public static AliasT tObjectAlias(final SymbolTable tab) {
2221: return new AliasT("java.lang.Object", tObject(tab));
2222: }
2223:
2224: public static ClassT tRuntimeException(final SymbolTable tab) {
2225: return tForName(tab, "java.lang.RuntimeException").toClass();
2226: }
2227:
2228: public static InterfaceT tSerializable(final SymbolTable tab) {
2229: return tForName(tab, "java.io.Serializable").toInterface();
2230: }
2231:
2232: public static ClassT tString(final SymbolTable tab) {
2233: return tForName(tab, "java.lang.String").toClass();
2234: }
2235:
2236: public static ClassT tThrowable(final SymbolTable tab) {
2237: return tForName(tab, "java.lang.Throwable").toClass();
2238: }
2239:
2240: public static String typeDeclString(final SymbolTable tab,
2241: final Object obj) {
2242: assert obj instanceof Type || obj instanceof List;
2243: if (obj instanceof Type)
2244: return typeToString(tab, true, (Type) obj);
2245: final StringBuilder result = new StringBuilder();
2246: for (final Type t : typeList((List) obj))
2247: result.append(typeToString(tab, true, t)).append(';');
2248: return result.toString();
2249: }
2250:
2251: public static VariableT typeDotField(final SymbolTable tab,
2252: final List<File> paths, final Type base,
2253: final boolean parents, final String name) {
2254: final List<VariableT> all = fieldsApplicableAndAccessible(tab,
2255: paths, base, parents, name);
2256: if (1 == all.size())
2257: return all.get(0);
2258: return null;
2259: }
2260:
2261: public static MethodT typeDotMethod(final SymbolTable tab,
2262: final List<File> paths, final Type baseT,
2263: final boolean parents, final String selector,
2264: final List<Type> actuals) {
2265: final List<MethodT> all = methodsApplicableAndAccessible(tab,
2266: paths, baseT, parents, selector, actuals);
2267: // chose the most specific method: see gosling_et_al_2000 Section 15.12.2.2.
2268: final List<MethodT> specific = mostSpecificMethods(tab, paths,
2269: all);
2270: final MethodT result;
2271: if (specific.size() == 1) {
2272: result = specific.get(0);
2273: } else {
2274: int nonAbstract = 0;
2275: MethodT any = null;
2276: for (final MethodT m : specific) {
2277: if (any == null)
2278: any = m;
2279: assert sameMethodSignature(m, any);
2280: if (!hasModifier(m, "abstract")) {
2281: any = m;
2282: nonAbstract++;
2283: }
2284: }
2285: assert nonAbstract <= 1;
2286: result = any;
2287: }
2288: if (null == result)
2289: return null;
2290: resolveIfAlias(tab, paths, typeToScopeName(baseT), result
2291: .getResult());
2292: return result;
2293: }
2294:
2295: public static ClassOrInterfaceT typeDotType(final SymbolTable tab,
2296: final List<File> paths, final ClassOrInterfaceT base,
2297: final boolean parents, final String selector) {
2298: if (recursiveTypeDotType)
2299: return null;
2300: recursiveTypeDotType = true;
2301: final List<Type> all = memberTypesApplicableAndAccessible(tab,
2302: paths, base, parents, selector);
2303: recursiveTypeDotType = false;
2304: if (1 == all.size())
2305: return (ClassOrInterfaceT) all.get(0);
2306: return null;
2307: }
2308:
2309: public static Type typeDotTypeOrField(final SymbolTable tab,
2310: final List<File> paths, final Type base,
2311: final boolean parents, final String selector) {
2312: assert isWrappedClassT(base) || isWrappedInterfaceT(base)
2313: || base.isArray();
2314: if (parents) {
2315: for (final Iterator<Type> i = new SuperTypesIter(tab,
2316: paths, base); i.hasNext();) {
2317: final Type member = typeDotTypeOrField(tab, paths, i
2318: .next(), false, selector);
2319: if (null != member)
2320: return member;
2321: }
2322: return null;
2323: }
2324: final VariableT field = typeDotField(tab, paths, base, false,
2325: selector);
2326: if (null != field)
2327: return field;
2328: return typeDotType(tab, paths, (ClassOrInterfaceT) base, false,
2329: selector);
2330: }
2331:
2332: @SuppressWarnings("unchecked")
2333: public static List<Type> typeList(final List list) {
2334: return list;
2335: }
2336:
2337: /** A descriptor is a JVM-internal string representation of a type of a field or method, see JVM
2338: * specification <a href="http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#1169">§4.3</a>. */
2339: public static String typeToDescriptor(final SymbolTable tab,
2340: final Type type) {
2341: if (isConstantT(type))
2342: return typeToDescriptor(tab, type.toAnnotated().getType());
2343: if (type.isBoolean())
2344: return "Z";
2345: if (type.isNumber()) {
2346: switch (((NumberT) type).getKind()) {
2347: case BYTE:
2348: return "B";
2349: case CHAR:
2350: return "C";
2351: case DOUBLE:
2352: return "D";
2353: case FLOAT:
2354: return "F";
2355: case INT:
2356: return "I";
2357: case LONG:
2358: return "J";
2359: case SHORT:
2360: return "S";
2361: }
2362: }
2363: if (type.isVoid())
2364: return "V";
2365: if (type.isArray())
2366: return "["
2367: + typeToDescriptor(tab, arrayElementType(type
2368: .toArray()));
2369: if (isWrappedClassT(type) || isWrappedInterfaceT(type))
2370: return "L"
2371: + qNameWithDollars(tab,
2372: resolveToRawClassOrInterfaceT(type))
2373: .replace('.', '/') + ";";
2374: if (type.isMethod()) {
2375: final StringBuilder b = new StringBuilder();
2376: b.append('(');
2377: for (final Type param : type.toMethod().getParameters())
2378: b.append(typeToDescriptor(tab, dereference(param)));
2379: b.append(')').append(
2380: typeToDescriptor(tab, type.toMethod().getResult()));
2381: return b.toString();
2382: }
2383: throw new Error();
2384: }
2385:
2386: static String typeToScopeName(final Type type) {
2387: if (null == type || type.isArray())
2388: return "";
2389: final String result = type.getScope();
2390: assert null != result;
2391: return result;
2392: }
2393:
2394: public static String typeToSimpleName(final Type type) {
2395: if (type.isAlias())
2396: return Utilities.unqualify(type.toAlias().getName());
2397: if (isWrappedClassT(type) || isWrappedInterfaceT(type))
2398: return resolveToRawClassOrInterfaceT(type).getName();
2399: assert type.isMethod();
2400: return type.toMethod().getName();
2401: }
2402:
2403: public static String typeToString(final SymbolTable tab,
2404: final boolean showDetails, final Type type) {
2405: final CharArrayWriter writer = new CharArrayWriter();
2406: final Printer printer = new Printer(writer);
2407: final TypePrinter typePrinter = new JavaTypePrinter(tab,
2408: showDetails, printer);
2409: typePrinter.dispatch(type);
2410: printer.flush();
2411: return writer.toString();
2412: }
2413:
2414: public static Type typeWithDimensions(final Type componentT,
2415: final int dim) {
2416: if (dim == 0)
2417: return componentT;
2418: final Type rec = typeWithDimensions(componentT, dim - 1);
2419: // FIXME: plugged in faux reference with faux type.
2420: final Type rec2 = rec.annotate().shape(
2421: new DynamicReference(NumberT.INT));
2422: return new ArrayT(rec2, true);
2423: }
2424:
2425: public static String unicodeUnescape(final String in) {
2426: if (!in.contains("\\u"))
2427: return in;
2428: final UnicodeUnescaper uu = new UnicodeUnescaper(
2429: new StringReader(in));
2430: final StringBuilder result = new StringBuilder(in.length());
2431: try {
2432: while (true) {
2433: final int c = uu.read();
2434: if (-1 == c)
2435: break;
2436: result.append((char) c);
2437: }
2438: } catch (final IOException e) {
2439: throw new Error("internal error", e);
2440: }
2441: return result.toString();
2442: }
2443:
2444: public static boolean zeroLiteral(final String s) {
2445: for (int i = 0; i < s.length(); i++) {
2446: final char c = s.charAt(i);
2447: if ('1' <= c && c <= '9')
2448: return false;
2449: if ('d' == c || 'D' == c || 'e' == c || 'E' == c
2450: || 'f' == c || 'F' == c)
2451: return true;
2452: }
2453: return true;
2454: }
2455: }
|