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 ConstructorReference { 029 inh ConstructorDecl ConstructorReference.unknownConstructor(); 030 031 syn lazy ConstructorDecl ClassReference.targetConstructor(FunctionDescriptor f) = 032 syntheticInstanceExpr(f).decl(); 033 034 syn nta lazy ClassInstanceExpr ClassReference.syntheticInstanceExpr(FunctionDescriptor f) { 035 List<Expr> arguments = new List<Expr>(); 036 for (int i = 0; i < f.method.getNumParameter(); i++) { 037 TypeDecl argumentType = f.method.getParameter(i).type(); 038 arguments.add(new SyntheticTypeAccess(argumentType)); 039 } 040 041 ClassInstanceExpr instanceExpr = null; 042 if (hasTypeArgument()) { 043 instanceExpr = new ParConstructorReferenceAccess( 044 (Access) getTypeAccess().treeCopyNoTransform(), arguments, 045 new Opt(), (List<Access>)getTypeArgumentList().treeCopyNoTransform(), f); 046 } else { 047 // Must check for raw reference type, and in that case infer using diamond (JLS 15.13.1) 048 boolean checkDiamond = true; 049 if (getTypeAccess().type().hostType() != null && !getTypeAccess().type().isStatic() 050 && getTypeAccess().type().hostType().isRawType()) { 051 checkDiamond = false; 052 } 053 if (getTypeAccess().type().isRawType() && checkDiamond) { 054 DiamondAccess diamond = new DiamondAccess((Access)getTypeAccess().treeCopyNoTransform()); 055 instanceExpr = new ConstructorReferenceAccess(diamond, arguments, f); 056 } else { 057 instanceExpr = new ConstructorReferenceAccess( 058 (Access) getTypeAccess().treeCopyNoTransform(), arguments, f); 059 } 060 } 061 return instanceExpr; 062 } 063 064 // Both array and class references always refer to types 065 eq ClassReference.getTypeArgument().nameType() = NameType.TYPE_NAME; 066 eq ConstructorReference.getTypeAccess().nameType() = NameType.TYPE_NAME; 067 068 syn lazy boolean ConstructorReference.congruentTo(FunctionDescriptor f); 069 070 eq ClassReference.congruentTo(FunctionDescriptor f) { 071 ConstructorDecl decl = targetConstructor(f); 072 if (unknownConstructor() == decl) { 073 return false; 074 } 075 if (!f.method.type().isVoid()) { 076 TypeDecl returnType = syntheticInstanceExpr(f).type(); 077 if (!returnType.assignConversionTo(f.method.type(), null)) { 078 return false; 079 } 080 } 081 return true; 082 } 083 084 eq ArrayReference.congruentTo(FunctionDescriptor f) { 085 if (f.method.getNumParameter() != 1) { 086 return false; 087 } 088 if (!f.method.getParameter(0).type().assignConversionTo(f.fromInterface().typeInt(), null)) { 089 return false; 090 } 091 if (!f.method.type().isVoid()) { 092 if (!getTypeAccess().type().assignConversionTo(f.method.type(), null)) { 093 return false; 094 } 095 } 096 return true; 097 } 098 099 100 syn lazy ArrayList<ConstructorDecl> ClassReference.potentiallyApplicableConstructors( 101 FunctionDescriptor f) { 102 TypeDecl classType = syntheticInstanceExpr(f).type(); 103 Collection<ConstructorDecl> col = classType.constructors(); 104 ArrayList<ConstructorDecl> applicable = new ArrayList<ConstructorDecl>(); 105 for (ConstructorDecl decl : col) { 106 if (!decl.accessibleFrom(hostType())) { 107 continue; 108 } 109 if (!(decl.arity() == f.method.arity())) { 110 continue; 111 } 112 if (hasTypeArgument()) { 113 if (!decl.isGeneric()) { 114 continue; 115 } 116 GenericConstructorDecl genDecl = decl.genericDecl(); 117 if (!(getNumTypeArgument() == genDecl.getNumTypeParameter())) { 118 continue; 119 } 120 } 121 applicable.add(decl); 122 } 123 return applicable; 124 } 125 126 // 15.13.1 127 syn lazy boolean ConstructorReference.isExact(); 128 129 syn lazy ConstructorDecl ClassReference.exactCompileTimeDeclaration() { 130 if (getTypeAccess().type().isRawType()) { 131 if (getTypeAccess().type().hostType() == null || getTypeAccess().type().isStatic() 132 || getTypeAccess().type().hostType().isRawType()) { 133 return unknownConstructor(); 134 } 135 } 136 TypeDecl classType = getTypeAccess().type(); 137 Collection<ConstructorDecl> col = classType.constructors(); 138 ArrayList<ConstructorDecl> applicable = new ArrayList<ConstructorDecl>(); 139 int foundCompatible = 0; 140 ConstructorDecl latestDecl = null; 141 142 for (ConstructorDecl decl : col) { 143 if (decl.accessibleFrom(hostType())) { 144 foundCompatible++; 145 latestDecl = decl; 146 } 147 } 148 if (foundCompatible != 1) { 149 return unknownConstructor(); 150 } 151 if (latestDecl.isVariableArity()) { 152 return unknownConstructor(); 153 } 154 if (latestDecl.isGeneric()) { 155 GenericConstructorDecl genericDecl = latestDecl.genericDecl(); 156 if (getNumTypeArgument() == genericDecl.getNumTypeParameter()) { 157 return latestDecl; 158 } else { 159 return unknownConstructor(); 160 } 161 } 162 return latestDecl; 163 } 164 165 eq ClassReference.isExact() = exactCompileTimeDeclaration() != unknownConstructor(); 166 167 eq ArrayReference.isExact() = true; 168 }