001 /* Copyright (c) 2014, Erik Hogeman <Erik.Hogemn@gmail.com> 002 * All rights reserved. 003 * 004 * Redistribution and use in source and binary forms, with or without 005 * modification, are permitted provided that the following conditions are met: 006 * 007 * * Redistributions of source code must retain the above copyright notice, 008 * this list of conditions and the following disclaimer. 009 * * Redistributions in binary form must reproduce the above copyright 010 * notice, this list of conditions and the following disclaimer in the 011 * documentation and/or other materials provided with the distribution. 012 * * Neither the name of the Lund University nor the names of its 013 * contributors may be used to endorse or promote products derived from 014 * this software without specific prior written permission. 015 * 016 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 017 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 018 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 019 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 020 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 021 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 022 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 023 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 024 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 025 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 026 * POSSIBILITY OF SUCH DAMAGE. 027 */ 028 aspect ConstructorReferenceToClass { 029 030 /* Build a nested ArrayTypeWithSizeAccess from the normal 031 ArrayTypeAccess. This is to be used when generating 032 the anonymous inner class which must instantiate a new 033 array according to the array reference */ 034 syn ArrayTypeAccess ArrayReference.getArrayTypeWithSizeAccess(Expr expr) { 035 ArrayTypeAccess startAccess = (ArrayTypeAccess) getTypeAccess().treeCopyNoTransform(); 036 return recursiveArrayTypeWithSizeAccess(startAccess, (Expr) expr.treeCopyNoTransform()); 037 } 038 039 syn ArrayTypeAccess ArrayReference.recursiveArrayTypeWithSizeAccess(ArrayTypeAccess access, Expr expr) { 040 if (!(access.getAccess() instanceof ArrayTypeAccess)) { 041 return new ArrayTypeWithSizeAccess(access.getAccess(), expr); 042 } else { 043 return new ArrayTypeAccess(recursiveArrayTypeWithSizeAccess((ArrayTypeAccess) access.getAccess(), expr)); 044 } 045 } 046 047 // Build an anonymous inner class for bytecode generation 048 syn nta lazy ClassInstanceExpr ConstructorReference.toClass() { 049 List<Access> implementsList = new List<Access>(); 050 InterfaceDecl iDecl = targetInterface(); 051 052 // First compute the interface implemented by the anonymous class 053 Access implementsInterface = iDecl.createQualifiedAccess(); 054 implementsList.add(implementsInterface); 055 056 // Next compute the BodyDecls for the anonymous class 057 List<BodyDecl> bodyDecls = new List<BodyDecl>(); 058 059 // Which means we must build the method overriding the abstract methods 060 061 Modifiers methodModifiers = new Modifiers(new List<Modifier>().add(new Modifier("public"))); 062 Access returnType = new SyntheticTypeAccess(iDecl.functionDescriptor().method.type()); 063 List<ParameterDeclaration> methodParams = toParameterList(); 064 List<Access> methodThrows = new List<Access>(); 065 for (TypeDecl throwsType : iDecl.functionDescriptor().throwsList) { 066 methodThrows.add(new SyntheticTypeAccess(throwsType)); 067 } 068 Opt<Block> methodBlock = new Opt<Block>(toBlock()); 069 MethodDecl method = new MethodDecl(methodModifiers, returnType, iDecl.functionDescriptor().method.name(), 070 methodParams, methodThrows, methodBlock); 071 072 bodyDecls.add(method); 073 074 /* Now the anonymous class can be built. Must use the type LambdaAnonymousDecl instead 075 of a normal AnonymousDecl in order for this and super keywords to get the type of the outer 076 scope. */ 077 LambdaAnonymousDecl anonymousDecl = new LambdaAnonymousDecl(new Modifiers(), "ConstructorReference", bodyDecls); 078 for (Access impl: implementsList) { 079 anonymousDecl.addImplements(impl); 080 } 081 082 return new ClassInstanceExpr((Access) implementsInterface.treeCopyNoTransform(), new List<Expr>(), new Opt<TypeDecl>(anonymousDecl)); 083 } 084 085 syn lazy Block ConstructorReference.toBlock(); 086 087 syn lazy List<ParameterDeclaration> ConstructorReference.toParameterList() { 088 List<ParameterDeclaration> list = new List<ParameterDeclaration>(); 089 for (int i = 0; i < targetInterface().functionDescriptor().method.getNumParameter(); i++) { 090 TypeDecl paramType = targetInterface().functionDescriptor().method.getParameter(i).type(); 091 String paramName = targetInterface().functionDescriptor().method.getParameter(i).name(); 092 list.add(new ParameterDeclaration(new SyntheticTypeAccess(paramType), paramName)); 093 } 094 return list; 095 } 096 097 eq ArrayReference.toBlock() { 098 // First, build an ArrayCreationExpr used in the block 099 String paramName = targetInterface().functionDescriptor().method.getParameter(0).name(); 100 VarAccess paramAccess = new VarAccess(paramName); 101 ArrayCreationExpr arrayExpr = new ArrayCreationExpr(getArrayTypeWithSizeAccess(paramAccess), new Opt()); 102 103 // Next build actual block 104 Stmt blockStmt = null; 105 if (targetInterface().functionDescriptor().method.type().isVoid()) { 106 blockStmt = new ExprStmt(arrayExpr); 107 } else { 108 blockStmt = new ReturnStmt(arrayExpr); 109 } 110 List<Stmt> stmtList = new List<Stmt>(); 111 stmtList.add(blockStmt); 112 return new Block(stmtList); 113 } 114 115 eq ClassReference.toBlock() { 116 List<Expr> arguments = new List<Expr>(); 117 for (int i = 0; i < targetInterface().functionDescriptor().method.getNumParameter(); i++) { 118 String paramName = targetInterface().functionDescriptor().method.getParameter(i).name(); 119 arguments.add(new VarAccess(paramName)); 120 } 121 122 ClassInstanceExpr instanceExpr = null; 123 if (hasTypeArgument()) { 124 instanceExpr = new ParClassInstanceExpr((Access) getTypeAccess().treeCopyNoTransform(), arguments, 125 new Opt(), (List<Access>)getTypeArgumentList().treeCopyNoTransform()); 126 } else { 127 if (getTypeAccess().type().isRawType()) { 128 DiamondAccess diamond = new DiamondAccess((Access) getTypeAccess().treeCopyNoTransform()); 129 instanceExpr = new ClassInstanceExpr(diamond, arguments); 130 } else { 131 instanceExpr = new ClassInstanceExpr((Access) getTypeAccess().treeCopyNoTransform(), arguments); 132 } 133 } 134 Stmt blockStmt = null; 135 if (targetInterface().functionDescriptor().method.type().isVoid()) { 136 blockStmt = new ExprStmt(instanceExpr); 137 } else { 138 blockStmt = new ReturnStmt(instanceExpr); 139 } 140 List<Stmt> stmtList = new List<Stmt>(); 141 stmtList.add(blockStmt); 142 return new Block(stmtList); 143 144 } 145 }