private List<PropertyNode> findTags(ClassNode classNode) {
    List<PropertyNode> tags = new ArrayList<PropertyNode>();
    List<PropertyNode> properties = classNode.getProperties();
    List<PropertyNode> potentialAliases = new ArrayList<PropertyNode>();
    for (PropertyNode property : properties) {
      if (property.isPublic()) {
        Expression initialExpression = property.getInitialExpression();
        if (initialExpression instanceof ClosureExpression) {
          ClosureExpression ce = (ClosureExpression) initialExpression;
          Parameter[] parameters = ce.getParameters();

          if (parameters.length <= 2) {
            tags.add(property);
            // force Closure type for DefaultGrailsTagLibClass
            property.setType(CLOSURE_CLASS_NODE);
          }
        } else if (initialExpression instanceof VariableExpression) {
          potentialAliases.add(property);
        }
      }
    }

    for (PropertyNode potentialAlias : potentialAliases) {
      VariableExpression pe = (VariableExpression) potentialAlias.getInitialExpression();

      String propertyName = pe.getName();
      PropertyNode property = classNode.getProperty(propertyName);
      if (property != null && tags.contains(property)) {
        potentialAlias.setType(CLOSURE_CLASS_NODE);
        tags.add(potentialAlias);
      }
    }
    return tags;
  }
  @Override
  protected void performInjectionInternal(
      String apiInstanceProperty, SourceUnit source, ClassNode classNode) {
    List<PropertyNode> tags = findTags(classNode);

    PropertyNode namespaceProperty = classNode.getProperty(NAMESPACE_PROPERTY);
    String namespace = GroovyPage.DEFAULT_NAMESPACE;
    if (namespaceProperty != null && namespaceProperty.isStatic()) {
      Expression initialExpression = namespaceProperty.getInitialExpression();
      if (initialExpression instanceof ConstantExpression) {
        namespace = initialExpression.getText();
      }
    }

    addGetTagLibNamespaceMethod(classNode, namespace);

    MethodCallExpression tagLibraryLookupMethodCall =
        new MethodCallExpression(
            new VariableExpression(apiInstanceProperty, ClassHelper.make(TagLibraryApi.class)),
            "getTagLibraryLookup",
            ZERO_ARGS);
    for (PropertyNode tag : tags) {
      String tagName = tag.getName();
      addAttributesAndBodyMethod(classNode, tagLibraryLookupMethodCall, tagName);
      addAttributesAndStringBodyMethod(classNode, tagName);
      addAttributesAndBodyMethod(classNode, tagLibraryLookupMethodCall, tagName, false);
      addAttributesAndBodyMethod(classNode, tagLibraryLookupMethodCall, tagName, true, false);
      addAttributesAndBodyMethod(classNode, tagLibraryLookupMethodCall, tagName, false, false);
    }
  }
 public static List<FieldNode> getInstanceNonPropertyFields(ClassNode cNode) {
   final List<FieldNode> result = new ArrayList<FieldNode>();
   for (FieldNode fNode : cNode.getFields()) {
     if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
       result.add(fNode);
     }
   }
   return result;
 }
 public static List<FieldNode> getSuperNonPropertyFields(ClassNode cNode) {
   final List<FieldNode> result;
   if (cNode == ClassHelper.OBJECT_TYPE) {
     result = new ArrayList<FieldNode>();
   } else {
     result = getSuperNonPropertyFields(cNode.getSuperClass());
   }
   for (FieldNode fNode : cNode.getFields()) {
     if (!fNode.isStatic() && cNode.getProperty(fNode.getName()) == null) {
       result.add(fNode);
     }
   }
   return result;
 }
 private void createConstructorMapCommon(ClassNode cNode, BlockStatement body) {
   final List<FieldNode> fList = cNode.getFields();
   for (FieldNode fNode : fList) {
     if (fNode.isPublic()) continue; // public fields will be rejected elsewhere
     if (cNode.getProperty(fNode.getName()) != null) continue; // a property
     if (fNode.isFinal() && fNode.isStatic()) continue;
     if (fNode.getName().contains("$")) continue; // internal field
     if (fNode.isFinal() && fNode.getInitialExpression() != null)
       body.addStatement(checkFinalArgNotOverridden(cNode, fNode));
     body.addStatement(createConstructorStatementDefault(fNode));
   }
   final Parameter[] params = new Parameter[] {new Parameter(HASHMAP_TYPE, "args")};
   doAddConstructor(
       cNode,
       new ConstructorNode(
           ACC_PUBLIC,
           params,
           ClassNode.EMPTY_ARRAY,
           new IfStatement(
               equalsNullExpr(new VariableExpression("args")), new EmptyStatement(), body)));
 }
  private boolean makeGetPropertyWithGetter(
      final Expression receiver,
      final ClassNode receiverType,
      final String methodName,
      final boolean safe,
      final boolean implicitThis) {
    // does a getter exists ?
    String getterName = "get" + MetaClassHelper.capitalize(methodName);
    MethodNode getterNode = receiverType.getGetterMethod(getterName);
    if (getterNode == null) {
      getterName = "is" + MetaClassHelper.capitalize(methodName);
      getterNode = receiverType.getGetterMethod(getterName);
    }
    if (getterNode != null
        && receiver instanceof ClassExpression
        && !CLASS_Type.equals(receiverType)
        && !getterNode.isStatic()) {
      return false;
    }

    // GROOVY-5561: if two files are compiled in the same source unit
    // and that one references the other, the getters for properties have not been
    // generated by the compiler yet (generated by the Verifier)
    PropertyNode propertyNode = receiverType.getProperty(methodName);
    if (propertyNode != null) {
      // it is possible to use a getter
      String prefix = "get";
      if (boolean_TYPE.equals(propertyNode.getOriginType())) {
        prefix = "is";
      }
      getterName = prefix + MetaClassHelper.capitalize(methodName);
      getterNode =
          new MethodNode(
              getterName,
              ACC_PUBLIC,
              propertyNode.getOriginType(),
              Parameter.EMPTY_ARRAY,
              ClassNode.EMPTY_ARRAY,
              EmptyStatement.INSTANCE);
      getterNode.setDeclaringClass(receiverType);
      if (propertyNode.isStatic()) getterNode.setModifiers(ACC_PUBLIC + ACC_STATIC);
    }
    if (getterNode != null) {
      MethodCallExpression call =
          new MethodCallExpression(receiver, getterName, ArgumentListExpression.EMPTY_ARGUMENTS);
      call.setSourcePosition(receiver);
      call.setMethodTarget(getterNode);
      call.setImplicitThis(implicitThis);
      call.setSafe(safe);
      call.visit(controller.getAcg());
      return true;
    }

    if (receiverType instanceof InnerClassNode && !receiverType.isStaticClass()) {
      if (makeGetPropertyWithGetter(
          receiver, receiverType.getOuterClass(), methodName, safe, implicitThis)) {
        return true;
      }
    }

    // go upper level
    ClassNode superClass = receiverType.getSuperClass();
    if (superClass != null) {
      return makeGetPropertyWithGetter(receiver, superClass, methodName, safe, implicitThis);
    }
    return false;
  }