use of org.codehaus.groovy.ast.PropertyNode in project groovy by apache.
the class GeneralUtils method getAllProperties.
public static List<PropertyNode> getAllProperties(final ClassNode type) {
ClassNode node = type;
List<PropertyNode> result = new ArrayList<>();
while (node != null) {
result.addAll(node.getProperties());
node = node.getSuperClass();
}
return result;
}
use of org.codehaus.groovy.ast.PropertyNode in project groovy by apache.
the class BeanUtils method addIfMissing.
private static void addIfMissing(ClassNode cNode, List<PropertyNode> result, Set<String> names, MethodNode mNode, ClassNode returnType, String propName, Statement getter, Statement setter) {
if (cNode.getProperty(propName) != null)
return;
if (names.contains(propName)) {
for (PropertyNode pn : result) {
if (pn.getName().equals(propName) && getter != null && pn.getGetterBlock() == null) {
pn.setGetterBlock(getter);
}
if (pn.getName().equals(propName) && setter != null && pn.getSetterBlock() == null) {
pn.setSetterBlock(setter);
}
}
} else {
result.add(new PropertyNode(propName, mNode.getModifiers(), returnType, cNode, null, getter, setter));
names.add(propName);
}
}
use of org.codehaus.groovy.ast.PropertyNode in project groovy by apache.
the class StaticTypeCheckingVisitor method existsProperty.
/**
* Checks whether a property exists on the receiver, or on any of the possible receiver classes (found in the
* temporary type information table)
*
* @param pexp a property expression
* @param readMode if true, look for property read, else for property set
* @param visitor if not null, when the property node is found, visit it with the provided visitor
* @return true if the property is defined in any of the possible receiver classes
*/
protected boolean existsProperty(final PropertyExpression pexp, final boolean readMode, final ClassCodeVisitorSupport visitor) {
super.visitPropertyExpression(pexp);
String propertyName = pexp.getPropertyAsString();
if (propertyName == null)
return false;
Expression objectExpression = pexp.getObjectExpression();
ClassNode objectExpressionType = getType(objectExpression);
if (objectExpression instanceof ConstructorCallExpression) {
ClassNode rawType = objectExpressionType.getPlainNodeReference();
inferDiamondType((ConstructorCallExpression) objectExpression, rawType);
}
// enclosing excludes classes that skip STC
Set<ClassNode> enclosingTypes = new LinkedHashSet<>();
enclosingTypes.add(typeCheckingContext.getEnclosingClassNode());
enclosingTypes.addAll(enclosingTypes.iterator().next().getOuterClasses());
boolean staticOnlyAccess = isClassClassNodeWrappingConcreteType(objectExpressionType);
if (staticOnlyAccess && "this".equals(propertyName)) {
// handle "Outer.this" for any level of nesting
ClassNode outer = objectExpressionType.getGenericsTypes()[0].getType();
ClassNode found = null;
for (ClassNode enclosingType : enclosingTypes) {
if (!enclosingType.isStaticClass() && outer.equals(enclosingType.getOuterClass())) {
found = enclosingType;
break;
}
}
if (found != null) {
storeType(pexp, outer);
return true;
}
}
boolean foundGetterOrSetter = false;
String capName = capitalize(propertyName);
Set<ClassNode> handledNodes = new HashSet<>();
List<Receiver<String>> receivers = new ArrayList<>();
addReceivers(receivers, makeOwnerList(objectExpression), pexp.isImplicitThis());
for (Receiver<String> receiver : receivers) {
ClassNode receiverType = receiver.getType();
if (receiverType.isArray() && "length".equals(propertyName)) {
pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
storeType(pexp, int_TYPE);
if (visitor != null) {
FieldNode length = new FieldNode("length", Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, int_TYPE, receiverType, null);
length.setDeclaringClass(receiverType);
visitor.visitField(length);
}
return true;
}
LinkedList<ClassNode> queue = new LinkedList<>();
queue.add(receiverType);
if (isPrimitiveType(receiverType)) {
queue.add(getWrapper(receiverType));
}
while (!queue.isEmpty()) {
ClassNode current = queue.remove();
if (!handledNodes.add(current))
continue;
FieldNode field = current.getDeclaredField(propertyName);
if (field == null) {
if (current.getSuperClass() != null)
queue.addFirst(current.getSuperClass());
Collections.addAll(queue, current.getInterfaces());
}
boolean staticOnly = (receiver.getData() == null ? staticOnlyAccess : false);
// as well; in case of static property access Class<Type> and Type are listed
if (isClassClassNodeWrappingConcreteType(current))
staticOnly = false;
field = allowStaticAccessToMember(field, staticOnly);
// skip property/accessor checks for "x.@field"
if (pexp instanceof AttributeExpression) {
if (field != null && storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
return true;
}
continue;
}
// skip property/accessor checks for "field", "this.field", "this.with { field }", etc. in declaring class of field
if (field != null && enclosingTypes.contains(current)) {
if (storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode)) {
return true;
}
}
MethodNode getter = findGetter(current, "is" + capName, pexp.isImplicitThis());
getter = allowStaticAccessToMember(getter, staticOnly);
if (getter == null)
getter = findGetter(current, getGetterName(propertyName), pexp.isImplicitThis());
getter = allowStaticAccessToMember(getter, staticOnly);
List<MethodNode> setters = findSetters(current, getSetterName(propertyName), /*enforce void:*/
false);
setters = allowStaticAccessToMember(setters, staticOnly);
// need to visit even if we only look for setters for compatibility
if (visitor != null && getter != null)
visitor.visitMethod(getter);
PropertyNode property = current.getProperty(propertyName);
property = allowStaticAccessToMember(property, staticOnly);
// prefer explicit getter or setter over property if receiver is not 'this'
if (property == null || !enclosingTypes.contains(receiverType)) {
if (readMode) {
if (getter != null && hasAccessToMember(enclosingTypes.iterator().next(), getter.getDeclaringClass(), getter.getModifiers())) {
ClassNode returnType = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, returnType);
storeTargetMethod(pexp, getter);
String delegationData = receiver.getData();
if (delegationData != null) {
pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
}
return true;
}
} else {
if (!setters.isEmpty()) {
if (visitor != null) {
if (field != null) {
visitor.visitField(field);
} else {
for (MethodNode setter : setters) {
// visiting setter will not infer the property type since return type is void, so visit a dummy field instead
FieldNode virtual = new FieldNode(propertyName, 0, setter.getParameters()[0].getOriginType(), current, null);
virtual.setDeclaringClass(setter.getDeclaringClass());
visitor.visitField(virtual);
}
}
}
SetterInfo info = new SetterInfo(current, getSetterName(propertyName), setters);
BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
if (enclosingBinaryExpression != null) {
putSetterInfo(enclosingBinaryExpression.getLeftExpression(), info);
}
String delegationData = receiver.getData();
if (delegationData != null) {
pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
}
pexp.removeNodeMetaData(READONLY_PROPERTY);
return true;
} else if (getter != null && field == null) {
// GROOVY-9127
pexp.putNodeMetaData(READONLY_PROPERTY, Boolean.TRUE);
}
}
}
if (property != null && storeProperty(property, pexp, receiverType, visitor, receiver.getData(), !readMode))
return true;
if (field != null && storeField(field, pexp, receiverType, visitor, receiver.getData(), !readMode))
return true;
foundGetterOrSetter = (foundGetterOrSetter || !setters.isEmpty() || getter != null);
}
// GROOVY-5568: the property may be defined by DGM
for (ClassNode dgmReceiver : isPrimitiveType(receiverType) ? new ClassNode[] { receiverType, getWrapper(receiverType) } : new ClassNode[] { receiverType }) {
List<MethodNode> methods = findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "get" + capName, ClassNode.EMPTY_ARRAY);
for (MethodNode method : findDGMMethodsByNameAndArguments(getSourceUnit().getClassLoader(), dgmReceiver, "is" + capName, ClassNode.EMPTY_ARRAY)) {
if (isPrimitiveBoolean(method.getReturnType()))
methods.add(method);
}
if (isUsingGenericsOrIsArrayUsingGenerics(dgmReceiver)) {
methods.removeIf(// GROOVY-10075: "List<Integer>" vs "List<String>"
method -> !typeCheckMethodsWithGenerics(dgmReceiver, ClassNode.EMPTY_ARRAY, method));
}
if (!methods.isEmpty()) {
List<MethodNode> bestMethods = chooseBestMethod(dgmReceiver, methods, ClassNode.EMPTY_ARRAY);
if (bestMethods.size() == 1) {
MethodNode getter = bestMethods.get(0);
if (visitor != null) {
visitor.visitMethod(getter);
}
ClassNode returnType = inferReturnTypeGenerics(dgmReceiver, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
storeInferredTypeForPropertyExpression(pexp, returnType);
if (readMode)
storeTargetMethod(pexp, getter);
return true;
}
}
}
// GROOVY-7996: check if receiver implements get(String)/set(String,Object) or propertyMissing(String) or $static_propertyMissing(String)?
if (!receiverType.isArray() && !isPrimitiveType(getUnwrapper(receiverType)) && pexp.isImplicitThis() && typeCheckingContext.getEnclosingClosure() != null) {
MethodNode mopMethod;
if (readMode) {
mopMethod = receiverType.getMethod("get", new Parameter[] { new Parameter(STRING_TYPE, "name") });
} else {
mopMethod = receiverType.getMethod("set", new Parameter[] { new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value") });
}
if (mopMethod == null)
mopMethod = receiverType.getMethod("propertyMissing", new Parameter[] { new Parameter(STRING_TYPE, "propertyName") });
if (mopMethod != null && !mopMethod.isStatic() && !mopMethod.isSynthetic()) {
pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE);
pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE);
pexp.removeNodeMetaData(INFERRED_TYPE);
visitor.visitMethod(mopMethod);
return true;
}
}
}
for (Receiver<String> receiver : receivers) {
ClassNode receiverType = receiver.getType();
ClassNode propertyType = getTypeForMapPropertyExpression(receiverType, pexp);
if (propertyType == null)
propertyType = getTypeForListPropertyExpression(receiverType, pexp);
if (propertyType == null)
propertyType = getTypeForSpreadExpression(receiverType, pexp);
if (propertyType == null)
continue;
if (visitor != null) {
// TODO: type inference on maps and lists, if possible
PropertyNode node = new PropertyNode(propertyName, Opcodes.ACC_PUBLIC, propertyType, receiver.getType(), null, null, null);
node.setDeclaringClass(receiver.getType());
visitor.visitProperty(node);
}
storeType(pexp, propertyType);
String delegationData = receiver.getData();
if (delegationData != null)
pexp.putNodeMetaData(IMPLICIT_RECEIVER, delegationData);
return true;
}
return foundGetterOrSetter;
}
use of org.codehaus.groovy.ast.PropertyNode in project groovy by apache.
the class TraitReceiverTransformer method transform.
@Override
public Expression transform(final Expression exp) {
ClassNode weavedType = weaved.getOriginType();
if (exp instanceof BinaryExpression) {
return transformBinaryExpression((BinaryExpression) exp, weavedType);
} else if (exp instanceof StaticMethodCallExpression) {
StaticMethodCallExpression call = (StaticMethodCallExpression) exp;
ClassNode ownerType = call.getOwnerType();
if (traitClass.equals(ownerType)) {
MethodCallExpression mce = callX(varX(weaved), call.getMethod(), transform(call.getArguments()));
mce.setSafe(false);
mce.setSpreadSafe(false);
mce.setImplicitThis(false);
mce.setSourcePosition(exp);
return mce;
}
} else if (exp instanceof MethodCallExpression) {
MethodCallExpression mce = (MethodCallExpression) exp;
String obj = mce.getObjectExpression().getText();
if (mce.isImplicitThis() || "this".equals(obj)) {
return transformMethodCallOnThis(mce);
} else if ("super".equals(obj)) {
return transformSuperMethodCall(mce);
}
} else if (exp instanceof FieldExpression) {
FieldNode fn = ((FieldExpression) exp).getField();
return transformFieldReference(exp, fn, fn.isStatic());
} else if (exp instanceof VariableExpression) {
VariableExpression vexp = (VariableExpression) exp;
Variable accessedVariable = vexp.getAccessedVariable();
if (accessedVariable instanceof FieldNode || accessedVariable instanceof PropertyNode) {
if (knownFields.contains(vexp.getName())) {
boolean isStatic = Modifier.isStatic(accessedVariable.getModifiers());
return transformFieldReference(exp, accessedVariable instanceof FieldNode ? (FieldNode) accessedVariable : ((PropertyNode) accessedVariable).getField(), isStatic);
} else {
PropertyExpression propertyExpression = propX(varX(weaved), vexp.getName());
propertyExpression.getProperty().setSourcePosition(exp);
return propertyExpression;
}
} else if (accessedVariable instanceof DynamicVariable && !inClosure) {
// GROOVY-9386
PropertyExpression propertyExpression = propX(varX(weaved), vexp.getName());
propertyExpression.getProperty().setSourcePosition(exp);
return propertyExpression;
}
if (vexp.isThisExpression()) {
VariableExpression variableExpression = varX(weaved);
variableExpression.setSourcePosition(exp);
return variableExpression;
}
if (vexp.isSuperExpression()) {
throwSuperError(vexp);
}
} else if (exp instanceof PropertyExpression) {
PropertyExpression pexp = (PropertyExpression) exp;
String obj = pexp.getObjectExpression().getText();
if (pexp.isImplicitThis() || "this".equals(obj)) {
String propName = pexp.getPropertyAsString();
if (knownFields.contains(propName)) {
FieldNode fn = new FieldNode(propName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
return transformFieldReference(exp, fn, false);
}
}
} else if (exp instanceof ClosureExpression) {
MethodCallExpression mce = callX(exp, "rehydrate", args(varX(weaved), varX(weaved), varX(weaved)));
mce.setImplicitThis(false);
mce.setSourcePosition(exp);
boolean oldInClosure = inClosure;
inClosure = true;
((ClosureExpression) exp).getCode().visit(this);
inClosure = oldInClosure;
// The rewrite we do is causing some troubles with type checking, which will
// not be able to perform closure parameter type inference
// so we store the replacement, which will be done *after* type checking.
exp.putNodeMetaData(TraitASTTransformation.POST_TYPECHECKING_REPLACEMENT, mce);
return exp;
}
// TODO: unary expressions (field++, field+=, ...)
return super.transform(exp);
}
use of org.codehaus.groovy.ast.PropertyNode in project groovy by apache.
the class ClassNodeUtils method hasPossibleStaticProperty.
/**
* Return true if we have a static accessor
*/
public static boolean hasPossibleStaticProperty(final ClassNode cNode, final String methodName) {
// assume explicit static method call checked first so we can assume a simple check here
if (!methodName.startsWith("get") && !methodName.startsWith("is")) {
return false;
}
String propName = getPropNameForAccessor(methodName);
PropertyNode pNode = getStaticProperty(cNode, propName);
return pNode != null && (methodName.startsWith("get") || isPrimitiveBoolean(pNode.getType()));
}
Aggregations