コード例 #1
0
    private void initTopLevelElement(PsiElement element) {
      CompiledPattern pattern = myGlobalVisitor.getContext().getPattern();

      PsiElement newElement = SkippingHandler.skipNodeIfNeccessary(element);

      if (element != newElement && newElement != null) {
        // way to support partial matching (ex. if ($condition$) )
        newElement.accept(this);
        pattern.setHandler(element, new LightTopLevelMatchingHandler(pattern.getHandler(element)));
      } else {
        myGlobalVisitor.setCodeBlockLevel(myGlobalVisitor.getCodeBlockLevel() + 1);

        for (PsiElement el = element.getFirstChild(); el != null; el = el.getNextSibling()) {
          if (GlobalCompilingVisitor.getFilter().accepts(el)) {
            if (el instanceof PsiWhiteSpace) {
              myGlobalVisitor.addLexicalNode(el);
            }
          } else {
            el.accept(this);

            MatchingHandler matchingHandler = pattern.getHandler(el);
            pattern.setHandler(
                el,
                element == myTopElement
                    ? new TopLevelMatchingHandler(matchingHandler)
                    : new LightTopLevelMatchingHandler(matchingHandler));

            /*
             do not assign light-top-level handlers through skipping, because it is incorrect;
             src: if (...) { st1; st2; }
             pattern: if (...) {$a$;}

             $a$ will have top-level handler, so matching will be considered as correct, although "st2;" is left!
            */
          }
        }

        myGlobalVisitor.setCodeBlockLevel(myGlobalVisitor.getCodeBlockLevel() - 1);
        pattern.setHandler(element, new TopLevelMatchingHandler(pattern.getHandler(element)));
      }
    }
コード例 #2
0
  private static boolean checkOptionalChildren(PsiElement root) {
    final boolean[] result = {true};

    root.accept(
        new PsiRecursiveElementWalkingVisitor() {
          @Override
          public void visitElement(PsiElement element) {
            super.visitElement(element);

            if (element instanceof LeafElement) {
              return;
            }

            final EquivalenceDescriptorProvider provider =
                EquivalenceDescriptorProvider.getInstance(element);
            if (provider == null) {
              return;
            }

            final EquivalenceDescriptor descriptor = provider.buildDescriptor(element);
            if (descriptor == null) {
              return;
            }

            for (SingleChildDescriptor childDescriptor : descriptor.getSingleChildDescriptors()) {
              if (childDescriptor.getType() == SingleChildDescriptor.MyType.OPTIONALLY_IN_PATTERN
                  && childDescriptor.getElement() == null) {
                result[0] = false;
              }
            }

            for (MultiChildDescriptor childDescriptor : descriptor.getMultiChildDescriptors()) {
              if (childDescriptor.getType() == MultiChildDescriptor.MyType.OPTIONALLY_IN_PATTERN) {
                PsiElement[] elements = childDescriptor.getElements();
                if (elements == null || elements.length == 0) {
                  result[0] = false;
                }
              }
            }
          }
        });
    return result[0];
  }
コード例 #3
0
  private static boolean checkErrorElements(PsiElement element) {
    final boolean[] result = {true};
    final int endOffset = element.getTextRange().getEndOffset();

    element.accept(
        new PsiRecursiveElementWalkingVisitor() {
          @Override
          public void visitElement(PsiElement element) {
            super.visitElement(element);

            if (element instanceof PsiErrorElement
                && element.getTextRange().getEndOffset() == endOffset) {
              result[0] = false;
            }
          }
        });

    return result[0];
  }
コード例 #4
0
  @Override
  public void compile(PsiElement[] elements, @NotNull final GlobalCompilingVisitor globalVisitor) {
    final PsiElement topElement = elements[0].getParent();
    final PsiElement element = elements.length > 1 ? topElement : elements[0];

    element.accept(new MyCompilingVisitor(globalVisitor, topElement));

    element.accept(
        new PsiRecursiveElementVisitor() {
          @Override
          public void visitElement(PsiElement element) {
            super.visitElement(element);
            if (DuplocatorUtil.isIgnoredNode(element)) {
              return;
            }
            CompiledPattern pattern = globalVisitor.getContext().getPattern();
            MatchingHandler handler = pattern.getHandler(element);

            if (!(handler instanceof SubstitutionHandler)
                && !(handler instanceof TopLevelMatchingHandler)
                && !(handler instanceof LightTopLevelMatchingHandler)) {
              pattern.setHandler(element, new SkippingHandler(handler));
            }

            // todo: simplify logic

            /*
            place skipping handler under top-level handler, because when we skip top-level node we can get non top-level handler, so
            depth matching won't be done!;
             */
            if (handler instanceof LightTopLevelMatchingHandler) {
              MatchingHandler delegate = ((LightTopLevelMatchingHandler) handler).getDelegate();
              if (!(delegate instanceof SubstitutionHandler)) {
                pattern.setHandler(
                    element, new LightTopLevelMatchingHandler(new SkippingHandler(delegate)));
              }
            }
          }
        });

    final Language baseLanguage = element.getContainingFile().getLanguage();

    // todo: try to optimize it: too heavy strategy!
    globalVisitor
        .getContext()
        .getPattern()
        .setStrategy(
            new MatchingStrategy() {
              @Override
              public boolean continueMatching(PsiElement start) {
                Language language = start.getLanguage();

                PsiFile file = start.getContainingFile();
                if (file != null) {
                  Language fileLanguage = file.getLanguage();
                  if (fileLanguage.isKindOf(language)) {
                    // dialect
                    language = fileLanguage;
                  }
                }

                return language == baseLanguage;
              }

              @Override
              public boolean shouldSkip(PsiElement element, PsiElement elementToMatchWith) {
                return DuplocatorUtil.shouldSkip(element, elementToMatchWith);
              }
            });
  }