public void checkNode(
      final SNode node,
      LanguageErrorsComponent component,
      final IOperationContext operationContext,
      IScope scope) {
    final ConstraintsDescriptor newDescriptor =
        ConceptRegistry.getInstance().getConstraintsDescriptorNew(node.getConceptFqName());

    final CheckingNodeContext checkingNodeContext =
        new jetbrains.mps.smodel.structure.CheckingNodeContext();

    if (SNodeOperations.getParent(node) != null) {
      component.addDependency(SNodeOperations.getParent(node));
    }
    if (SNodeOperations.getParent(node) != null
        && !(jetbrains.mps.smodel.SNodeOperations.isUnknown(SNodeOperations.getParent(node)))) {
      final SNode link = SNodeOperations.getContainingLinkDeclaration(node);
      if (link == null) {
        component.addError(node, "Child in a role with unknown link", null);
        return;
      }
      boolean canBeChild =
          component.runCheckingAction(
              new _FunctionTypes._return_P0_E0<Boolean>() {
                public Boolean invoke() {
                  return ModelConstraintsManager.canBeChild(
                      newDescriptor,
                      node.getConceptFqName(),
                      operationContext,
                      SNodeOperations.getParent(node),
                      link,
                      checkingNodeContext);
                }
              });
      if (!(canBeChild)) {
        SNode rule = getBreakingNodeAndClearContext(checkingNodeContext);
        component.addError(
            node,
            "Node " + node + " cannot be child of node " + SNodeOperations.getParent(node),
            rule);
      }
    }

    if (node.isRoot()) {
      boolean canBeRoot =
          component.runCheckingAction(
              new _FunctionTypes._return_P0_E0<Boolean>() {
                public Boolean invoke() {
                  return ModelConstraintsManager.canBeRoot(
                      newDescriptor,
                      operationContext,
                      node.getConceptFqName(),
                      SNodeOperations.getModel(node),
                      checkingNodeContext);
                }
              });
      if (!(canBeRoot)) {
        SNode rule = getBreakingNodeAndClearContext(checkingNodeContext);
        component.addError(node, "Not rootable concept added as root", rule);
      }
    }

    for (SNode child : SNodeOperations.getChildren(node)) {
      component.addDependency(child);
      final SNode childConcept = SNodeOperations.getConceptDeclaration(child);
      final SNode childLink = SNodeOperations.getContainingLinkDeclaration(child);
      if (childLink == null) {
        continue;
      }
      boolean canBeParent =
          component.runCheckingAction(
              new _FunctionTypes._return_P0_E0<Boolean>() {
                public Boolean invoke() {
                  return ModelConstraintsManager.canBeParent(
                      newDescriptor,
                      node,
                      childConcept,
                      childLink,
                      operationContext,
                      checkingNodeContext);
                }
              });
      if (!(canBeParent)) {
        SNode rule = getBreakingNodeAndClearContext(checkingNodeContext);
        component.addError(node, "Node " + node + " cannot be parent of node " + child, rule);
      }

      // todo: do it right, with runCheckingAction!
      if (!(ModelConstraintsManager.canBeAncestor(
          node, childConcept, operationContext, checkingNodeContext))) {
        SNode rule =
            SNodeOperations.cast(
                getBreakingNodeAndClearContext(checkingNodeContext),
                "jetbrains.mps.lang.constraints.structure.ConstraintFunction_CanBeAnAncestor");
        component.addError(
            child,
            "Concept "
                + SLinkOperations.getTarget(
                    SNodeOperations.as(
                        SNodeOperations.getParent(rule),
                        "jetbrains.mps.lang.constraints.structure.ConceptConstraints"),
                    "concept",
                    false)
                + " cannot be ancestor of node "
                + child,
            rule);
      }
    }

    // Properties validation
    SNode concept = SNodeOperations.getConceptDeclaration(node);
    component.addDependency(concept);
    ConceptAndSuperConceptsScope chs = new ConceptAndSuperConceptsScope(concept);
    for (SNode parentConcept : chs.getConcepts()) {
      component.addDependency(parentConcept);
    }
    List<SNode> props =
        ((List<SNode>)
            chs.getNodes(
                new Condition<SNode>() {
                  public boolean met(SNode n) {
                    return SNodeOperations.isInstanceOf(
                        n, "jetbrains.mps.lang.structure.structure.PropertyDeclaration");
                  }
                }));
    for (SNode p : ListSequence.fromList(props)) {
      final PropertySupport ps = PropertySupport.getPropertySupport(p);
      final String propertyName = SPropertyOperations.getString(p, "name");
      if (propertyName == null) {
        LOG.error(
            "Property declaration has a null name, declaration id: "
                + p.getSNodeId()
                + ", model: "
                + SNodeOperations.getModel(p).getSModelFqName());
        continue;
      }
      final String value = ps.fromInternalValue(node.getProperty(propertyName));
      final PropertyConstraintsDescriptor propertyDescriptor =
          newDescriptor.getProperty(propertyName);
      boolean canSetValue =
          component.runCheckingAction(
              new _FunctionTypes._return_P0_E0<Boolean>() {
                public Boolean invoke() {
                  return ps.canSetValue(
                      propertyDescriptor, node, propertyName, value, operationContext.getScope());
                }
              });
      if (!(canSetValue)) {
        // RE-2426 Ñ disabling the "Property constraint violation for property" error messages

        /*
        // TODO this is a hack for anonymous classes
        if ("name".equals(SPropertyOperations.getString(p, "name")) && ("AnonymousClass".equals(SPropertyOperations.getString(concept, "name")) || "InternalAnonymousClass".equals(SPropertyOperations.getString(concept, "name")))) {
          continue;
        }
        // todo find a rule
        component.addError(node, "Property constraint violation for property \"" + SPropertyOperations.getString(p, "name") + "\"", null, new PropertyMessageTarget(SPropertyOperations.getString(p, "name")));
        */
      }
    }
  }
  private static List<INodeSubstituteAction> createActions_internal(
      SNode parentNode,
      SNode currentChild,
      SNode childConcept,
      IChildNodeSetter childSetter,
      IOperationContext context) {
    List<INodeSubstituteAction> resultActions = new ArrayList<INodeSubstituteAction>();
    if (childConcept == null) {
      return resultActions;
    }

    // special case
    if (childConcept == SModelUtil.getBaseConcept()) {
      if ((currentChild == null
          || currentChild.getConcept().getId().equals(SNodeUtil.concept_BaseConcept))) {
        resultActions = new ArrayList<INodeSubstituteAction>();
        ISearchScope conceptsSearchScope =
            SModelSearchUtil.createConceptsFromModelLanguagesScope(
                parentNode.getModel(), true, context.getScope());
        List<SNode> allVisibleConcepts = conceptsSearchScope.getNodes();
        for (final SNode visibleConcept : allVisibleConcepts) {
          resultActions.add(
              new DefaultChildNodeSubstituteAction(
                  visibleConcept, parentNode, currentChild, childSetter, context.getScope()) {
                public String getMatchingText(String pattern) {
                  return getMatchingText(pattern, true, true);
                }

                public String getVisibleMatchingText(String pattern) {
                  return getMatchingText(pattern);
                }

                public String getDescriptionText(String pattern) {
                  String fqName = NameUtil.nodeFQName(visibleConcept);
                  return "lang: "
                      + NameUtil.compactNamespace(NameUtil.namespaceFromConceptFQName(fqName));
                }

                public Icon getIconFor(String pattern) {
                  return getIconFor(pattern, true);
                }
              });
        }
        return resultActions;
      }

      // pretend we are going to substitute more concrete concept
      childConcept = ChildSubstituteActionsUtil.getRefinedChildConcept(currentChild);
    }

    Language primaryLanguage = SModelUtil.getDeclaringLanguage(childConcept);
    if (primaryLanguage == null) {
      LOG.error(
          "Couldn't build actions : couldn't get declaring language for concept "
              + org.jetbrains.mps.openapi.model.SNodeUtil.getDebugText(childConcept));
      return resultActions;
    }

    List<SNode> allBuilders =
        ChildSubstituteActionsUtil.getActionsBuilders(
            parentNode, currentChild, childConcept, childSetter, context);
    if (!ChildSubstituteActionsUtil.containsRemoveDefaults(allBuilders)) {
      resultActions.addAll(
          createPrimaryChildSubstituteActions(
              parentNode, currentChild, childConcept, childSetter, context));
    }

    for (SNode builder : allBuilders) {
      List<INodeSubstituteAction> addActions =
          ChildSubstituteActionsUtil.invokeActionFactory(
              builder, parentNode, currentChild, childConcept, childSetter, context);
      resultActions.addAll(addActions);
    }

    for (SNode builder : allBuilders) {
      resultActions =
          ChildSubstituteActionsUtil.applyActionFilter(
              builder, resultActions, parentNode, currentChild, childConcept, context);
    }

    if (childSetter instanceof DefaultChildNodeSetter
        || childSetter instanceof AbstractCellMenuPart_ReplaceNode_CustomNodeConcept
            && currentChild != null) {
      SNode linkDeclaration;
      if (childSetter instanceof DefaultChildNodeSetter) {
        linkDeclaration = ((DefaultChildNodeSetter) childSetter).myLinkDeclaration;
      } else {
        linkDeclaration = currentChild.getRoleLink();
      }

      Iterator<INodeSubstituteAction> it = resultActions.iterator();
      while (it.hasNext()) {
        INodeSubstituteAction action = it.next();

        SNode conceptNode = action.getOutputConcept();
        if (conceptNode == null) {
          continue;
        }

        if (!ModelConstraintsManager.canBeParent(parentNode, conceptNode, linkDeclaration, context)
            || !ModelConstraintsManager.canBeAncestor(parentNode, conceptNode, context)) {
          it.remove();
        }
      }
    }

    return resultActions;
  }