void RedundantMemberInitCheck::registerMatchers(MatchFinder *Finder) {
  auto Construct =
      cxxConstructExpr(
          hasDeclaration(cxxConstructorDecl(hasParent(
              cxxRecordDecl(unless(isTriviallyDefaultConstructible()))))))
          .bind("construct");

  Finder->addMatcher(
      cxxConstructorDecl(
          unless(isDelegatingConstructor()),
          ofClass(unless(
              anyOf(isUnion(), ast_matchers::isTemplateInstantiation()))),
          forEachConstructorInitializer(
              cxxCtorInitializer(isWritten(),
                                 withInitializer(ignoringImplicit(Construct)),
                                 unless(forField(hasType(isConstQualified()))))
                  .bind("init"))),
      this);
}
void MultiProcessing3D<OriginalGenerator,MutableGenerator>::subdivideGenerator()
{
    // To start with, determine which multi-blocks are read and which are written
    std::vector<bool> isWritten(multiBlocks.size());
    generator.getModificationPattern(isWritten);
    PLB_ASSERT( isWritten.size() == multiBlocks.size() );

    // The reference block (the one for which the envelope is included if
    //   the domain generator.appliesTo() include the envelope) is either the
    //   multi-block which is written, or the first multi-block if all are read-only.
    pluint referenceBlock = 0;
    for (pluint iBlock=0; iBlock<isWritten.size(); ++iBlock) {
        if (isWritten[iBlock]) {
            referenceBlock = iBlock;
            break;
        }
    }

    // In debug mode, make sure that a most one multi-block is written when envelope is included.
#ifdef PLB_DEBUG
    if ( BlockDomain::usesEnvelope(generator.appliesTo()) ) {
        plint numWritten = 0;
        for (pluint iBlock=0; iBlock<isWritten.size(); ++iBlock) {
            if (isWritten[iBlock]) {
                ++numWritten;
            }
        }
        PLB_ASSERT( numWritten <= 1 );
    }
#endif
    
    // The first step is to access the domains of the the atomic blocks, as well
    //   as their IDs in each of the coupled multi blocks. The domain corresponds
    //   to the bulk and/or to the envelope, depending on the value of generator.appliesTo().
    std::vector<std::vector<DomainAndId3D> > domainsWithId(multiBlocks.size());
    for (pluint iMulti=0; iMulti<multiBlocks.size(); ++iMulti) {
        std::vector<plint> const& blocks
            = multiBlocks[iMulti]->getMultiBlockManagement().getLocalInfo().getBlocks();
        for (pluint iBlock=0; iBlock<blocks.size(); ++iBlock) {
            plint blockId = blocks[iBlock];
            SmartBulk3D bulk(multiBlocks[iMulti]->getMultiBlockManagement(), blockId);
            switch (generator.appliesTo()) {
                case BlockDomain::bulk:
                    domainsWithId[iMulti].push_back(DomainAndId3D(bulk.getBulk(),blockId));
                    break;
                case BlockDomain::bulkAndEnvelope:
                    // It's only the reference block that should have the envelope. However, we start
                    //   by assigning bulk and envelope to all of them, and eliminate overlapping
                    //   envelope components further down.
                    domainsWithId[iMulti].push_back(DomainAndId3D(bulk.computeEnvelope(),blockId));
                    break;
                case BlockDomain::envelope:
                    // For the reference block, we restrict ourselves to the envelope, because
                    //   that's the desired domain of application.
                    if (iMulti==referenceBlock) {
                        std::vector<Box3D> envelopeOnly;
                        except(bulk.computeEnvelope(), bulk.getBulk(), envelopeOnly);
                        for (pluint iEnvelope=0; iEnvelope<envelopeOnly.size(); ++iEnvelope) {
                            domainsWithId[iMulti].push_back(DomainAndId3D(envelopeOnly[iEnvelope], blockId));
                        }
                    }
                    // For the other blocks, we need to take bulk and envelope, because all these domains
                    //   potentially intersect with the envelope of the reference block.
                    else {
                        domainsWithId[iMulti].push_back(DomainAndId3D(bulk.computeEnvelope(),blockId));
                    }
                    break;
            }
        }
    }

    // If the multi-blocks are not at the same level of grid refinement, the level
    //   of the first block is taken as reference, and the coordinates of the other
    //   blocks are rescaled accordingly.
    plint firstLevel = multiBlocks[0]->getMultiBlockManagement().getRefinementLevel();
    for (pluint iMulti=1; iMulti<multiBlocks.size(); ++iMulti) {
        plint relativeLevel = firstLevel -
                             multiBlocks[iMulti]->getMultiBlockManagement().getRefinementLevel();
        if (relativeLevel != 0) {
            for (pluint iBlock=0; iBlock<domainsWithId[iMulti].size(); ++iBlock) {
                domainsWithId[iMulti][iBlock].domain =
                    global::getDefaultMultiScaleManager().scaleBox (
                            domainsWithId[iMulti][iBlock].domain, relativeLevel );
            }
        }
    }

    // If the envelopes are included as well, it is assumed that at most one of
    //   the multi blocks has write-access. All others (those that have read-only
    //   access) need to be non-overlaping, to avoid multiple writes on the cells
    //   of the write-access-multi-block. Thus, overlaps are now eliminitated in
    //   the read-access-multi-blocks.
    if ( BlockDomain::usesEnvelope(generator.appliesTo()) ) {
        for (pluint iMulti=0; iMulti<multiBlocks.size(); ++iMulti) {
            if (!isWritten[iMulti]) {
                std::vector<DomainAndId3D> nonOverlapBlocks(getNonOverlapingBlocks(domainsWithId[iMulti]));
                domainsWithId[iMulti].swap(nonOverlapBlocks);
            }
        }
    }

    // This is the heart of the whole procedure: intersecting atomic blocks
    //   between all coupled multi blocks are identified.
    std::vector<Box3D> finalDomains;
    std::vector<std::vector<plint> > finalIds;
    intersectDomainsAndIds(domainsWithId, finalDomains, finalIds);

    // And, to end with, re-create processor generators adapted to the
    //   computed domains of intersection.
    if ( BlockDomain::usesEnvelope(generator.appliesTo()) ) {
        // In case the envelope is included, periodicity must be explicitly treated.
        //   Indeed, the user indicates the domain of applicability with respect to
        //   bulk nodes only. The generator is therefore shifted in all space directions
        //   to englobe periodic boundary nodes as well.
        plint shiftX = firstMultiBlock->getNx();
        plint shiftY = firstMultiBlock->getNy();
        plint shiftZ = firstMultiBlock->getNz();
        PeriodicitySwitch3D const& periodicity = firstMultiBlock->periodicity();
        for (plint orientX=-1; orientX<=+1; ++orientX) {
            for (plint orientY=-1; orientY<=+1; ++orientY) {
                for (plint orientZ=-1; orientZ<=+1; ++orientZ) {
                    if (periodicity.get(orientX,orientY,orientZ)) {
                        extractGeneratorOnBlocks( finalDomains, finalIds,
                                                  orientX*shiftX, orientY*shiftY, orientZ*shiftZ );
                    }
                }
            }
        }
    }
    else {
        extractGeneratorOnBlocks(finalDomains, finalIds);
    }
}