langtools/src/share/classes/com/sun/tools/javac/code/TypeAnnotations.java
changeset 8050 4b78c27c217f
parent 8030 0074833e36c6
parent 8049 6f996a6c9b02
child 8051 85a8fae9d6e0
equal deleted inserted replaced
8030:0074833e36c6 8050:4b78c27c217f
     1 /*
       
     2  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.sun.tools.javac.code;
       
    27 
       
    28 import javax.lang.model.element.ElementKind;
       
    29 
       
    30 import com.sun.tools.javac.code.Symbol.VarSymbol;
       
    31 import com.sun.tools.javac.tree.JCTree;
       
    32 import com.sun.tools.javac.tree.TreeInfo;
       
    33 import com.sun.tools.javac.tree.TreeScanner;
       
    34 import com.sun.tools.javac.tree.JCTree.*;
       
    35 import com.sun.tools.javac.util.Context;
       
    36 import com.sun.tools.javac.util.List;
       
    37 import com.sun.tools.javac.util.ListBuffer;
       
    38 
       
    39 /**
       
    40  * Contains operations specific to processing type annotations
       
    41  */
       
    42 public class TypeAnnotations {
       
    43     private static final Context.Key<TypeAnnotations> key
       
    44         = new Context.Key<TypeAnnotations>();
       
    45 
       
    46     public static TypeAnnotations instance(Context context) {
       
    47         TypeAnnotations instance = context.get(key);
       
    48         if (instance == null)
       
    49             instance = new TypeAnnotations(context);
       
    50         return instance;
       
    51     }
       
    52 
       
    53     protected TypeAnnotations(Context context) {
       
    54         context.put(key, this);
       
    55     }
       
    56 
       
    57     public void taFillAndLift(JCClassDecl tree, boolean visitBodies) {
       
    58 //308        new TypeAnnotationPositions().scan(tree);
       
    59 //308        new TypeAnnotationLift().scan(tree);
       
    60     }
       
    61 
       
    62     private static class TypeAnnotationPositions extends TreeScanner {
       
    63 
       
    64         private ListBuffer<JCTree> frames = ListBuffer.lb();
       
    65         private void push(JCTree t) { frames = frames.prepend(t); }
       
    66         private JCTree pop() { return frames.next(); }
       
    67         private JCTree peek2() { return frames.toList().tail.head; }
       
    68 
       
    69         @Override
       
    70         public void scan(JCTree tree) {
       
    71             push(tree);
       
    72             super.scan(tree);
       
    73             pop();
       
    74         }
       
    75 
       
    76         private boolean inClass = false;
       
    77 
       
    78         @Override
       
    79         public void visitClassDef(JCClassDecl tree) {
       
    80            if (!inClass) {
       
    81                // Do not recurse into nested and inner classes since
       
    82                // TransTypes.visitClassDef makes an invocation for each class
       
    83                // separately.
       
    84                inClass = true;
       
    85                try {
       
    86                    super.visitClassDef(tree);
       
    87                } finally {
       
    88                    inClass = false;
       
    89                }
       
    90            }
       
    91         }
       
    92 
       
    93         private TypeAnnotationPosition resolveFrame(JCTree tree, JCTree frame,
       
    94                 List<JCTree> path, TypeAnnotationPosition p) {
       
    95             switch (frame.getKind()) {
       
    96                 case TYPE_CAST:
       
    97                     p.type = TargetType.TYPECAST;
       
    98                     p.pos = frame.pos;
       
    99                     return p;
       
   100 
       
   101                 case INSTANCE_OF:
       
   102                     p.type = TargetType.INSTANCEOF;
       
   103                     p.pos = frame.pos;
       
   104                     return p;
       
   105 
       
   106                 case NEW_CLASS:
       
   107                     p.type = TargetType.NEW;
       
   108                     p.pos = frame.pos;
       
   109                     return p;
       
   110 
       
   111                 case NEW_ARRAY:
       
   112                     p.type = TargetType.NEW;
       
   113                     p.pos = frame.pos;
       
   114                     return p;
       
   115 
       
   116                 case ANNOTATION_TYPE:
       
   117                 case CLASS:
       
   118                 case ENUM:
       
   119                 case INTERFACE:
       
   120                     p.pos = frame.pos;
       
   121                     if (((JCClassDecl)frame).extending == tree) {
       
   122                         p.type = TargetType.CLASS_EXTENDS;
       
   123                         p.type_index = -1;
       
   124                     } else if (((JCClassDecl)frame).implementing.contains(tree)) {
       
   125                         p.type = TargetType.CLASS_EXTENDS;
       
   126                         p.type_index = ((JCClassDecl)frame).implementing.indexOf(tree);
       
   127                     } else if (((JCClassDecl)frame).typarams.contains(tree)) {
       
   128                         p.type = TargetType.CLASS_TYPE_PARAMETER;
       
   129                         p.parameter_index = ((JCClassDecl)frame).typarams.indexOf(tree);
       
   130                     } else
       
   131                         throw new AssertionError();
       
   132                     return p;
       
   133 
       
   134                 case METHOD: {
       
   135                     JCMethodDecl frameMethod = (JCMethodDecl)frame;
       
   136                     p.pos = frame.pos;
       
   137                     if (frameMethod.receiverAnnotations.contains(tree))
       
   138                         p.type = TargetType.METHOD_RECEIVER;
       
   139                     else if (frameMethod.thrown.contains(tree)) {
       
   140                         p.type = TargetType.THROWS;
       
   141                         p.type_index = frameMethod.thrown.indexOf(tree);
       
   142                     } else if (((JCMethodDecl)frame).restype == tree) {
       
   143                         p.type = TargetType.METHOD_RETURN_GENERIC_OR_ARRAY;
       
   144                     } else if (frameMethod.typarams.contains(tree)) {
       
   145                         p.type = TargetType.METHOD_TYPE_PARAMETER;
       
   146                         p.parameter_index = frameMethod.typarams.indexOf(tree);
       
   147                     } else
       
   148                         throw new AssertionError();
       
   149                     return p;
       
   150                 }
       
   151                 case MEMBER_SELECT: {
       
   152                     JCFieldAccess fieldFrame = (JCFieldAccess)frame;
       
   153                     if ("class".contentEquals(fieldFrame.name)) {
       
   154                         p.type = TargetType.CLASS_LITERAL;
       
   155                         p.pos = TreeInfo.innermostType(fieldFrame.selected).pos;
       
   156                     } else
       
   157                         throw new AssertionError();
       
   158                     return p;
       
   159                 }
       
   160                 case PARAMETERIZED_TYPE: {
       
   161                     TypeAnnotationPosition nextP;
       
   162                     if (((JCTypeApply)frame).clazz == tree)
       
   163                         nextP = p; // generic: RAW; noop
       
   164                     else if (((JCTypeApply)frame).arguments.contains(tree))
       
   165                         p.location = p.location.prepend(
       
   166                                 ((JCTypeApply)frame).arguments.indexOf(tree));
       
   167                     else
       
   168                         throw new AssertionError();
       
   169 
       
   170                     List<JCTree> newPath = path.tail;
       
   171                     return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
       
   172                 }
       
   173 
       
   174                 case ARRAY_TYPE: {
       
   175                     p.location = p.location.prepend(0);
       
   176                     List<JCTree> newPath = path.tail;
       
   177                     return resolveFrame(newPath.head, newPath.tail.head, newPath, p);
       
   178                 }
       
   179 
       
   180                 case TYPE_PARAMETER:
       
   181                     if (path.tail.tail.head.getTag() == JCTree.CLASSDEF) {
       
   182                         JCClassDecl clazz = (JCClassDecl)path.tail.tail.head;
       
   183                         p.type = TargetType.CLASS_TYPE_PARAMETER_BOUND;
       
   184                         p.parameter_index = clazz.typarams.indexOf(path.tail.head);
       
   185                         p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
       
   186                     } else if (path.tail.tail.head.getTag() == JCTree.METHODDEF) {
       
   187                         JCMethodDecl method = (JCMethodDecl)path.tail.tail.head;
       
   188                         p.type = TargetType.METHOD_TYPE_PARAMETER_BOUND;
       
   189                         p.parameter_index = method.typarams.indexOf(path.tail.head);
       
   190                         p.bound_index = ((JCTypeParameter)frame).bounds.indexOf(tree);
       
   191                     } else
       
   192                         throw new AssertionError();
       
   193                     p.pos = frame.pos;
       
   194                     return p;
       
   195 
       
   196                 case VARIABLE:
       
   197                     VarSymbol v = ((JCVariableDecl)frame).sym;
       
   198                     p.pos = frame.pos;
       
   199                     switch (v.getKind()) {
       
   200                         case LOCAL_VARIABLE:
       
   201                             p.type = TargetType.LOCAL_VARIABLE; break;
       
   202                         case FIELD:
       
   203                             p.type = TargetType.FIELD_GENERIC_OR_ARRAY; break;
       
   204                         case PARAMETER:
       
   205                             p.type = TargetType.METHOD_PARAMETER_GENERIC_OR_ARRAY;
       
   206                             p.parameter_index = methodParamIndex(path, frame);
       
   207                             break;
       
   208                         default: throw new AssertionError();
       
   209                     }
       
   210                     return p;
       
   211 
       
   212 //308                case ANNOTATED_TYPE: {
       
   213 //308                    List<JCTree> newPath = path.tail;
       
   214 //308                    return resolveFrame(newPath.head, newPath.tail.head,
       
   215 //308                            newPath, p);
       
   216 //308                }
       
   217 
       
   218                 case METHOD_INVOCATION: {
       
   219                     JCMethodInvocation invocation = (JCMethodInvocation)frame;
       
   220                     if (!invocation.typeargs.contains(tree))
       
   221                         throw new AssertionError("{" + tree + "} is not an argument in the invocation: " + invocation);
       
   222                     p.type = TargetType.METHOD_TYPE_ARGUMENT;
       
   223                     p.pos = invocation.pos;
       
   224                     p.type_index = invocation.typeargs.indexOf(tree);
       
   225                     return p;
       
   226                 }
       
   227 
       
   228                 case EXTENDS_WILDCARD:
       
   229                 case SUPER_WILDCARD: {
       
   230                     p.type = TargetType.WILDCARD_BOUND;
       
   231                     List<JCTree> newPath = path.tail;
       
   232 
       
   233                     TypeAnnotationPosition wildcard =
       
   234                         resolveFrame(newPath.head, newPath.tail.head, newPath,
       
   235                                 new TypeAnnotationPosition());
       
   236                     if (!wildcard.location.isEmpty())
       
   237                         wildcard.type = wildcard.type.getGenericComplement();
       
   238                     p.wildcard_position = wildcard;
       
   239                     p.pos = frame.pos;
       
   240                     return p;
       
   241                 }
       
   242             }
       
   243             return p;
       
   244         }
       
   245 
       
   246         private void setTypeAnnotationPos(List<JCTypeAnnotation> annotations, TypeAnnotationPosition position) {
       
   247             for (JCTypeAnnotation anno : annotations) {
       
   248                 anno.annotation_position = position;
       
   249                 anno.attribute_field.position = position;
       
   250             }
       
   251         }
       
   252 
       
   253         @Override
       
   254         public void visitNewArray(JCNewArray tree) {
       
   255             findPosition(tree, tree, tree.annotations);
       
   256             int dimAnnosCount = tree.dimAnnotations.size();
       
   257 
       
   258             // handle annotations associated with dimentions
       
   259             for (int i = 0; i < dimAnnosCount; ++i) {
       
   260                 TypeAnnotationPosition p = new TypeAnnotationPosition();
       
   261                 p.type = TargetType.NEW_GENERIC_OR_ARRAY;
       
   262                 p.pos = tree.pos;
       
   263                 p.location = p.location.append(i);
       
   264                 setTypeAnnotationPos(tree.dimAnnotations.get(i), p);
       
   265             }
       
   266 
       
   267             // handle "free" annotations
       
   268             int i = dimAnnosCount == 0 ? 0 : dimAnnosCount - 1;
       
   269             JCExpression elemType = tree.elemtype;
       
   270             while (elemType != null) {
       
   271                 if (elemType.getTag() == JCTree.ANNOTATED_TYPE) {
       
   272                     JCAnnotatedType at = (JCAnnotatedType)elemType;
       
   273                     TypeAnnotationPosition p = new TypeAnnotationPosition();
       
   274                     p.type = TargetType.NEW_GENERIC_OR_ARRAY;
       
   275                     p.pos = tree.pos;
       
   276                     p.location = p.location.append(i);
       
   277                     setTypeAnnotationPos(at.annotations, p);
       
   278                     elemType = at.underlyingType;
       
   279                 } else if (elemType.getTag() == JCTree.TYPEARRAY) {
       
   280                     ++i;
       
   281                     elemType = ((JCArrayTypeTree)elemType).elemtype;
       
   282                 } else
       
   283                     break;
       
   284             }
       
   285 
       
   286             // find annotations locations of initializer elements
       
   287             scan(tree.elems);
       
   288         }
       
   289 
       
   290         @Override
       
   291         public void visitAnnotatedType(JCAnnotatedType tree) {
       
   292             findPosition(tree, peek2(), tree.annotations);
       
   293             super.visitAnnotatedType(tree);
       
   294         }
       
   295 
       
   296         @Override
       
   297         public void visitMethodDef(JCMethodDecl tree) {
       
   298             TypeAnnotationPosition p = new TypeAnnotationPosition();
       
   299             p.type = TargetType.METHOD_RECEIVER;
       
   300             setTypeAnnotationPos(tree.receiverAnnotations, p);
       
   301             super.visitMethodDef(tree);
       
   302         }
       
   303         @Override
       
   304         public void visitTypeParameter(JCTypeParameter tree) {
       
   305             findPosition(tree, peek2(), tree.annotations);
       
   306             super.visitTypeParameter(tree);
       
   307         }
       
   308 
       
   309         void findPosition(JCTree tree, JCTree frame, List<JCTypeAnnotation> annotations) {
       
   310             if (!annotations.isEmpty()) {
       
   311                 TypeAnnotationPosition p =
       
   312                         resolveFrame(tree, frame, frames.toList(),
       
   313                                 new TypeAnnotationPosition());
       
   314                 if (!p.location.isEmpty())
       
   315                     p.type = p.type.getGenericComplement();
       
   316                 setTypeAnnotationPos(annotations, p);
       
   317             }
       
   318         }
       
   319 
       
   320         private int methodParamIndex(List<JCTree> path, JCTree param) {
       
   321             List<JCTree> curr = path;
       
   322             if (curr.head != param)
       
   323                 curr = path.tail;
       
   324             JCMethodDecl method = (JCMethodDecl)curr.tail.head;
       
   325             return method.params.indexOf(param);
       
   326         }
       
   327     }
       
   328 
       
   329     private static class TypeAnnotationLift extends TreeScanner {
       
   330         List<Attribute.TypeCompound> recordedTypeAnnotations = List.nil();
       
   331 
       
   332         boolean isInner = false;
       
   333         @Override
       
   334         public void visitClassDef(JCClassDecl tree) {
       
   335             if (isInner) {
       
   336                 // tree is an inner class tree.  stop now.
       
   337                 // TransTypes.visitClassDef makes an invocation for each class
       
   338                 // separately.
       
   339                 return;
       
   340             }
       
   341             isInner = true;
       
   342             List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
       
   343             recordedTypeAnnotations = List.nil();
       
   344             try {
       
   345                 super.visitClassDef(tree);
       
   346             } finally {
       
   347                 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
       
   348                 recordedTypeAnnotations = prevTAs;
       
   349             }
       
   350         }
       
   351 
       
   352         @Override
       
   353         public void visitMethodDef(JCMethodDecl tree) {
       
   354             List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
       
   355             recordedTypeAnnotations = List.nil();
       
   356             try {
       
   357                 super.visitMethodDef(tree);
       
   358             } finally {
       
   359                 tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
       
   360                 recordedTypeAnnotations = prevTAs;
       
   361             }
       
   362         }
       
   363 
       
   364         @Override
       
   365         public void visitVarDef(JCVariableDecl tree) {
       
   366             List<Attribute.TypeCompound> prevTAs = recordedTypeAnnotations;
       
   367             recordedTypeAnnotations = List.nil();
       
   368             ElementKind kind = tree.sym.getKind();
       
   369             if (kind == ElementKind.LOCAL_VARIABLE && tree.mods.annotations.nonEmpty()) {
       
   370                 // need to lift the annotations
       
   371                 TypeAnnotationPosition position = new TypeAnnotationPosition();
       
   372                 position.pos = tree.pos;
       
   373                 position.type = TargetType.LOCAL_VARIABLE;
       
   374                 for (Attribute.Compound attribute : tree.sym.attributes_field) {
       
   375                     Attribute.TypeCompound tc =
       
   376                         new Attribute.TypeCompound(attribute.type, attribute.values, position);
       
   377                     recordedTypeAnnotations = recordedTypeAnnotations.append(tc);
       
   378                 }
       
   379             }
       
   380             try {
       
   381                 super.visitVarDef(tree);
       
   382             } finally {
       
   383                 if (kind.isField() || kind == ElementKind.LOCAL_VARIABLE)
       
   384                     tree.sym.typeAnnotations = tree.sym.typeAnnotations.appendList(recordedTypeAnnotations);
       
   385                 recordedTypeAnnotations = kind.isField() ? prevTAs : prevTAs.appendList(recordedTypeAnnotations);
       
   386             }
       
   387         }
       
   388 
       
   389         @Override
       
   390         public void visitApply(JCMethodInvocation tree) {
       
   391             scan(tree.meth);
       
   392             scan(tree.typeargs);
       
   393             scan(tree.args);
       
   394         }
       
   395 
       
   396         public void visitAnnotation(JCAnnotation tree) {
       
   397             if (tree instanceof JCTypeAnnotation)
       
   398                 recordedTypeAnnotations = recordedTypeAnnotations.append(((JCTypeAnnotation)tree).attribute_field);
       
   399             super.visitAnnotation(tree);
       
   400         }
       
   401     }
       
   402 
       
   403 }