private static void visitFieldNode(FieldNode fNode) { final ClassNode cNode = fNode.getDeclaringClass(); final List<PropertyNode> pList = cNode.getProperties(); PropertyNode foundProp = null; for (PropertyNode pNode : pList) { if (pNode.getName().equals(fNode.getName())) { foundProp = pNode; break; } } if (foundProp != null) { revertVisibility(fNode); pList.remove(foundProp); } }
private static Expression syncTarget(FieldNode fieldNode) { return fieldNode.isStatic() ? classX(fieldNode.getDeclaringClass()) : varX("this"); }
public void visitField(final FieldNode node) { if (visitor!=null) visitor.visitField(node); ClassNode declaringClass = node.getDeclaringClass(); if (declaringClass!=null) { if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, ClassHelper.LIST_TYPE)) { boolean spread = declaringClass.getDeclaredField(node.getName()) != node; pexp.setSpreadSafe(spread); } rType.set(declaringClass); } }
private static Parameter[] getParams(List<FieldNode> fields, ClassNode cNode) { Parameter[] parameters = new Parameter[fields.size()]; for (int i = 0; i < parameters.length; i++) { FieldNode fNode = fields.get(i); Map<String,ClassNode> genericsSpec = createGenericsSpec(fNode.getDeclaringClass()); extractSuperClassGenerics(fNode.getType(), cNode, genericsSpec); ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, fNode.getType()); parameters[i] = new Parameter(correctedType, fNode.getName()); } return parameters; }
private static void addMethod(FieldNode fieldNode, BlockStatement body, ClassNode type) { int visibility = ACC_PUBLIC; if (fieldNode.isStatic()) visibility |= ACC_STATIC; String propName = MetaClassHelper.capitalize(fieldNode.getName().substring(1)); ClassNode declaringClass = fieldNode.getDeclaringClass(); addGeneratedMethod(declaringClass, "get" + propName, visibility, type, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, body); if (ClassHelper.boolean_TYPE.equals(type)) { addGeneratedMethod(declaringClass, "is" + propName, visibility, type, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, stmt(callThisX("get" + propName))); } }
private static boolean isValidFieldNodeForByteCodeAccess(FieldNode fn, ClassNode accessingNode) { if (fn == null) return false; ClassNode declaringClass = fn.getDeclaringClass(); // same class is always allowed access if (Modifier.isPublic(fn.getModifiers()) || declaringClass.equals(accessingNode)) return true; boolean samePackages = samePackages(declaringClass.getPackageName(), accessingNode.getPackageName()); // protected means same class or same package, or subclass if (Modifier.isProtected(fn.getModifiers()) && (samePackages || accessingNode.isDerivedFrom(declaringClass))) { return true; } if (!fn.isPrivate()) { // package private is the only modifier left. It means same package is allowed, subclass not, same class is return samePackages; } return false; }
private boolean storeField(FieldNode field, boolean returnTrueIfFieldExists, PropertyExpression expressionToStoreOn, ClassNode receiver, ClassCodeVisitorSupport visitor, String delegationData, boolean lhsOfAssignment) { if (field == null || !returnTrueIfFieldExists) return false; if (visitor != null) visitor.visitField(field); storeWithResolve(field.getOriginType(), receiver, field.getDeclaringClass(), field.isStatic(), expressionToStoreOn); checkOrMarkPrivateAccess(expressionToStoreOn, field, lhsOfAssignment); if (delegationData != null) { expressionToStoreOn.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData); } return true; }
static void visitField(ErrorCollecting xform, AnnotationNode node, FieldNode fieldNode) { final Expression soft = node.getMember("soft"); final Expression init = getInitExpr(xform, fieldNode); String backingFieldName = "$" + fieldNode.getName(); fieldNode.rename(backingFieldName); fieldNode.setModifiers(ACC_PRIVATE | (fieldNode.getModifiers() & (~(ACC_PUBLIC | ACC_PROTECTED)))); PropertyNode pNode = fieldNode.getDeclaringClass().getProperty(backingFieldName); if (pNode != null) { fieldNode.getDeclaringClass().getProperties().remove(pNode); } if (soft instanceof ConstantExpression && ((ConstantExpression) soft).getValue().equals(true)) { createSoft(fieldNode, init); } else { create(fieldNode, init); // @Lazy not meaningful with primitive so convert to wrapper if needed if (ClassHelper.isPrimitiveType(fieldNode.getType())) { fieldNode.setType(ClassHelper.getWrapper(fieldNode.getType())); } } }
private static FieldNode createFieldCopy(ClassNode buildee, FieldNode fNode) { Map<String,ClassNode> genericsSpec = createGenericsSpec(fNode.getDeclaringClass()); extractSuperClassGenerics(fNode.getType(), buildee, genericsSpec); ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, fNode.getType()); return new FieldNode(fNode.getName(), fNode.getModifiers(), correctedType, buildee, DEFAULT_INITIAL_VALUE); }
private static boolean isDirectAccessAllowed(FieldNode a, ClassNode receiver, boolean isSamePackage) { ClassNode declaringClass = a.getDeclaringClass().redirect(); ClassNode receiverType = receiver.redirect(); // first, direct access from within the class or inner class nodes if (declaringClass.equals(receiverType)) return true; if (receiverType instanceof InnerClassNode) { while (receiverType instanceof InnerClassNode) { if (declaringClass.equals(receiverType)) return true; receiverType = receiverType.getOuterClass(); } } // no getter return a.isPublic() || (a.isProtected() && isSamePackage); }
private static void addGetter(FieldNode fNode, ClassNode componentType) { ClassNode cNode = fNode.getDeclaringClass(); BlockStatement body = new BlockStatement(); Parameter[] params = new Parameter[1]; params[0] = new Parameter(ClassHelper.int_TYPE, "index"); body.addStatement(stmt(indexX(varX(fNode), varX(params[0])))); addGeneratedMethod(cNode, makeName(fNode, "get"), getModifiers(fNode), componentType, params, null, body); }
private MethodNode createBuilderMethodForField(ClassNode builder, List<FieldNode> fields, String prefix, int fieldPos) { String fieldName = fields.get(fieldPos).getName(); String setterName = getSetterName(prefix, fieldName); GenericsType[] gtypes = new GenericsType[fields.size()]; List<Expression> argList = new ArrayList<Expression>(); for (int i = 0; i < fields.size(); i++) { gtypes[i] = i == fieldPos ? new GenericsType(ClassHelper.make(SET.class)) : makePlaceholder(i); argList.add(i == fieldPos ? propX(varX("this"), constX(fieldName)) : varX(fields.get(i).getName())); } ClassNode returnType = makeClassSafeWithGenerics(builder, gtypes); FieldNode fNode = fields.get(fieldPos); Map<String,ClassNode> genericsSpec = createGenericsSpec(fNode.getDeclaringClass()); extractSuperClassGenerics(fNode.getType(), builder, genericsSpec); ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, fNode.getType()); return new MethodNode(setterName, ACC_PUBLIC, returnType, params(param(correctedType, fieldName)), NO_EXCEPTIONS, block( stmt(assignX(propX(varX("this"), constX(fieldName)), varX(fieldName, correctedType))), returnS(ctorX(returnType, args(argList))) )); }
private static void addHolderClassIdiomBody(BlockStatement body, FieldNode fieldNode, Expression initExpr) { final ClassNode declaringClass = fieldNode.getDeclaringClass(); final ClassNode fieldType = fieldNode.getType(); final int visibility = ACC_PRIVATE | ACC_STATIC; final String fullName = declaringClass.getName() + "$" + fieldType.getNameWithoutPackage() + "Holder_" + fieldNode.getName().substring(1); final InnerClassNode holderClass = new InnerClassNode(declaringClass, fullName, visibility, ClassHelper.OBJECT_TYPE); final String innerFieldName = "INSTANCE"; // we have two options: // (1) embed initExpr within holder class but redirect field access/method calls to declaring class members // (2) keep initExpr within a declaring class method that is only called by the holder class // currently we have gone with (2) for simplicity with only a slight memory footprint increase in the declaring class final String initializeMethodName = (fullName + "_initExpr").replace('.', '_'); addGeneratedMethod(declaringClass, initializeMethodName, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, fieldType, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, returnS(initExpr)); holderClass.addField(innerFieldName, ACC_PRIVATE | ACC_STATIC | ACC_FINAL, fieldType, callX(declaringClass, initializeMethodName)); final Expression innerField = propX(classX(holderClass), innerFieldName); declaringClass.getModule().addClass(holderClass); body.addStatement(returnS(innerField)); }
private static void createSoftSetter(FieldNode fieldNode, ClassNode type) { final BlockStatement body = new BlockStatement(); final Expression fieldExpr = varX(fieldNode); final String name = "set" + MetaClassHelper.capitalize(fieldNode.getName().substring(1)); final Parameter parameter = param(type, "value"); final Expression paramExpr = varX(parameter); body.addStatement(ifElseS( notNullX(paramExpr), assignS(fieldExpr, ctorX(SOFT_REF, paramExpr)), assignS(fieldExpr, NULL_EXPR) )); int visibility = ACC_PUBLIC; if (fieldNode.isStatic()) visibility |= ACC_STATIC; ClassNode declaringClass = fieldNode.getDeclaringClass(); addGeneratedMethod(declaringClass, name, visibility, ClassHelper.VOID_TYPE, params(parameter), ClassNode.EMPTY_ARRAY, body); }
private static void addSetter(FieldNode fNode, ClassNode componentType) { ClassNode cNode = fNode.getDeclaringClass(); BlockStatement body = new BlockStatement(); Parameter[] theParams = params( new Parameter(ClassHelper.int_TYPE, "index"), new Parameter(componentType, "value")); body.addStatement(assignS(indexX(varX(fNode), varX(theParams[0])), varX(theParams[1]))); addGeneratedMethod(cNode, makeName(fNode, "set"), getModifiers(fNode), ClassHelper.VOID_TYPE, theParams, null, body); }
public ClassNode resolveType(final Expression exp, final ClassNode current) { if (exp instanceof ClassExpression) return ClassHelper.CLASS_Type; OptimizingStatementWriter.StatementMeta meta = exp.getNodeMetaData(OptimizingStatementWriter.StatementMeta.class); ClassNode type = null; if (meta != null) type = meta.type; if (type != null) return type; if (exp instanceof VariableExpression) { VariableExpression ve = (VariableExpression) exp; if (ve.isClosureSharedVariable()) return ve.getType(); type = ve.getOriginType(); if (ve.getAccessedVariable() instanceof FieldNode) { FieldNode fn = (FieldNode) ve.getAccessedVariable(); if (!fn.getDeclaringClass().equals(current)) return fn.getOriginType(); } } else if (exp instanceof Variable) { Variable v = (Variable) exp; type = v.getOriginType(); } else { type = exp.getType(); } return type.redirect(); } }
private static Expression tryTransformPrivateFieldAccess(VariableExpression expr) { FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS); if (field == null) { field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_MUTATION); } if (field != null) { // access to a private field from a section of code that normally doesn't have access to it, like a // closure or an inner class VariableExpression receiver = new VariableExpression("this"); PropertyExpression pexp = new PropertyExpression( receiver, expr.getName() ); pexp.setImplicitThis(true); pexp.getProperty().setSourcePosition(expr); // put the receiver inferred type so that the class writer knows that it will have to call a bridge method receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass()); // add inferred type information pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType()); return pexp; } return null; } }
/** * Given a field node, checks if we are accessing or setting a private field from an inner class. */ private void checkOrMarkPrivateAccess(Expression source, FieldNode fn, boolean lhsOfAssignment) { ClassNode enclosingClassNode = typeCheckingContext.getEnclosingClassNode(); ClassNode declaringClass = fn.getDeclaringClass(); if (fn != null && Modifier.isPrivate(fn.getModifiers()) && (declaringClass != enclosingClassNode || typeCheckingContext.getEnclosingClosure() != null) && declaringClass.getModule() == enclosingClassNode.getModule()) { if (!lhsOfAssignment && enclosingClassNode.isDerivedFrom(declaringClass)) { // check for a public/protected getter since JavaBean getters haven't been recognised as properties // at this point and we don't want private field access for that case which will be handled later boolean isPrimBool = fn.getOriginType().equals(ClassHelper.boolean_TYPE); String suffix = Verifier.capitalize(fn.getName()); MethodNode getterNode = findValidGetter(enclosingClassNode, "get" + suffix); if (getterNode == null && isPrimBool) { getterNode = findValidGetter(enclosingClassNode, "is" + suffix); } if (getterNode != null) { source.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, getterNode.getReturnType()); return; } } StaticTypesMarker marker = lhsOfAssignment ? StaticTypesMarker.PV_FIELDS_MUTATION : StaticTypesMarker.PV_FIELDS_ACCESS; addPrivateFieldOrMethodAccess(source, declaringClass, marker, fn); } }
protected Expression transformVariableExpression(VariableExpression ve) { Variable v = ve.getAccessedVariable(); if (v instanceof DynamicVariable) { Expression result = findStaticFieldOrPropAccessorImportFromModule(v.getName()); if (result != null) { setSourcePosition(result, ve); if (inAnnotation) { result = transformInlineConstants(result); } return result; } } else if (v instanceof FieldNode) { if (inSpecialConstructorCall) { // GROOVY-8819 FieldNode fn = (FieldNode) v; ClassNode declaringClass = fn.getDeclaringClass(); if (fn.isStatic() && currentClass.isDerivedFrom(declaringClass)) { Expression result = new PropertyExpression(new ClassExpression(declaringClass), v.getName()); result.setSourcePosition(ve); return result; } } } return ve; }
public void visit(ASTNode[] nodes, SourceUnit source) { init(nodes, source); AnnotatedNode parent = (AnnotatedNode) nodes[1]; AnnotationNode node = (AnnotationNode) nodes[0]; if (!MY_TYPE.equals(node.getClassNode())) return; if (parent instanceof FieldNode) { FieldNode fNode = (FieldNode) parent; ClassNode cNode = fNode.getDeclaringClass(); if (cNode.getProperty(fNode.getName()) == null) { addError("Error during " + MY_TYPE_NAME + " processing. Field '" + fNode.getName() + "' doesn't appear to be a property; incorrect visibility?", fNode); return; } ClassNode fType = fNode.getType(); if (fType.isArray()) { addArraySetter(fNode); addArrayGetter(fNode); } else if (fType.isDerivedFrom(LIST_TYPE)) { addListSetter(fNode); addListGetter(fNode); } else { addError("Error during " + MY_TYPE_NAME + " processing. Non-Indexable property '" + fNode.getName() + "' found. Type must be array or list but found " + fType.getName(), fNode); } } }