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 PolyExpressions { 029 syn lazy boolean Expr.isBooleanExpression() = 030 !isPolyExpression() && type().isBoolean(); 031 032 eq ParExpr.isBooleanExpression() = 033 getExpr().isBooleanExpression(); 034 035 eq ClassInstanceExpr.isBooleanExpression() { 036 if (getAccess() instanceof TypeAccess) { 037 TypeAccess typeAccess = (TypeAccess) getAccess(); 038 return typeAccess.name().equals("Boolean"); 039 } 040 return false; 041 } 042 043 eq MethodAccess.isBooleanExpression() { 044 MethodDecl decl = decl(); 045 if (decl instanceof ParMethodDecl) { 046 return ((ParMethodDecl) decl).genericMethodDecl().type().isBoolean(); 047 } else { 048 return decl.type().isBoolean(); 049 } 050 } 051 052 eq ConditionalExpr.isBooleanExpression() = 053 isBooleanConditional(); 054 055 syn lazy boolean ConditionalExpr.isBooleanConditional() = 056 getTrueExpr().isBooleanExpression() && getFalseExpr().isBooleanExpression(); 057 058 059 syn lazy boolean Expr.isNumericExpression() = 060 !isPolyExpression() && type().isNumericType(); 061 062 eq MethodAccess.isNumericExpression() { 063 MethodDecl decl = decl(); 064 if (decl instanceof ParMethodDecl) { 065 return ((ParMethodDecl) decl).genericMethodDecl().type().isNumericType(); 066 } else { 067 return decl.type().isNumericType(); 068 } 069 } 070 071 eq ConditionalExpr.isNumericExpression() = 072 isNumericConditional(); 073 074 syn lazy boolean ConditionalExpr.isNumericConditional() = 075 getTrueExpr().isNumericExpression() && getFalseExpr().isNumericExpression(); 076 077 syn lazy boolean ConditionalExpr.isReferenceConditional() = 078 !isBooleanConditional() && !isNumericConditional(); 079 080 syn lazy boolean Expr.isPolyExpression() = false; 081 082 eq ConditionalExpr.isPolyExpression() = 083 isReferenceConditional() && (assignmentContext() || invocationContext()); 084 085 // 15.9 086 eq ClassInstanceExpr.isPolyExpression() = 087 (getAccess() instanceof DiamondAccess) && (assignmentContext() || invocationContext()); 088 089 // 15.8.5 090 eq ParExpr.isPolyExpression() = 091 getExpr().isPolyExpression(); 092 093 eq LambdaExpr.isPolyExpression() = true; 094 eq MethodReference.isPolyExpression() = true; 095 eq ConstructorReference.isPolyExpression() = true; 096 097 // 15.12 098 eq ParMethodAccess.isPolyExpression() = false; 099 eq MethodAccess.isPolyExpression() { 100 if (!assignmentContext() && !invocationContext()) { 101 return false; 102 } 103 if (!decl().isGeneric()) { 104 return false; 105 } 106 GenericMethodDecl genericDecl = decl().genericDecl(); 107 return genericDecl.typeVariableInReturn(); 108 } 109 110 syn lazy boolean GenericMethodDecl.typeVariableInReturn() { 111 if (!getTypeAccess().usesTypeVariable()) { 112 return false; 113 } 114 ASTNode current = getTypeAccess(); 115 LinkedList<ASTNode> list = new LinkedList<ASTNode>(); 116 list.add(current); 117 boolean foundUse = false; 118 while (!list.isEmpty()) { 119 current = list.poll(); 120 for (int i = 0; i < current.getNumChild(); i++) { 121 list.add(current.getChild(i)); 122 } 123 if (current instanceof TypeAccess) { 124 TypeAccess typeAccess = (TypeAccess)current; 125 if (typeAccess.type().isTypeVariable()) { 126 for (int i = 0; i < getNumTypeParameter(); i++) { 127 if (typeAccess.type() == getTypeParameter(i)) { 128 foundUse = true; 129 break; 130 } 131 } 132 if (foundUse) { 133 break; 134 } 135 } 136 } 137 } 138 return foundUse; 139 } 140 141 // This can be used to check assignment compatibility without worrying about poly expressions type 142 syn lazy boolean Expr.assignConversionTo(TypeDecl type) = type().assignConversionTo(type, this); 143 144 eq LambdaExpr.assignConversionTo(TypeDecl type) { 145 if (!type.isFunctionalInterface()) { 146 return false; 147 } 148 FunctionDescriptor f = ((InterfaceDecl) type).functionDescriptor(); 149 return congruentTo(f); 150 } 151 152 eq MethodReference.assignConversionTo(TypeDecl type) { 153 if (!type.isFunctionalInterface()) { 154 return false; 155 } 156 FunctionDescriptor f = ((InterfaceDecl) type).functionDescriptor(); 157 return congruentTo(f); 158 } 159 160 eq ConstructorReference.assignConversionTo(TypeDecl type) { 161 if (!type.isFunctionalInterface()) { 162 return false; 163 } 164 FunctionDescriptor f = ((InterfaceDecl) type).functionDescriptor(); 165 return congruentTo(f); 166 } 167 168 eq ParExpr.assignConversionTo(TypeDecl type) = 169 getExpr().assignConversionTo(type); 170 171 eq ConditionalExpr.assignConversionTo(TypeDecl type) { 172 if (!isPolyExpression()) { 173 return type().assignConversionTo(type, this); 174 } else { 175 return getTrueExpr().assignConversionTo(type) && getFalseExpr().assignConversionTo(type); 176 } 177 } 178 179 eq ClassInstanceExpr.assignConversionTo(TypeDecl type) { 180 if (!isPolyExpression()) { 181 return super.assignConversionTo(type); 182 } else { 183 return ((DiamondAccess) getAccess()).getTypeAccess().type().assignConversionTo( 184 type, ((DiamondAccess)getAccess()).getTypeAccess()); 185 } 186 } 187 188 }