Beispiel #1
0
  public static PsiElement[] parsePattern(
      Project project,
      String context,
      String pattern,
      FileType fileType,
      Language language,
      String extension,
      boolean physical) {
    int offset = context.indexOf(PATTERN_PLACEHOLDER);

    final int patternLength = pattern.length();
    final String patternInContext = context.replace(PATTERN_PLACEHOLDER, pattern);

    final String ext = extension != null ? extension : fileType.getDefaultExtension();
    final String name = "__dummy." + ext;
    final PsiFileFactory factory = PsiFileFactory.getInstance(project);

    final PsiFile file =
        language == null
            ? factory.createFileFromText(
                name, fileType, patternInContext, LocalTimeCounter.currentTime(), physical, true)
            : factory.createFileFromText(name, language, patternInContext, physical, true);
    if (file == null) {
      return PsiElement.EMPTY_ARRAY;
    }

    final List<PsiElement> result = new ArrayList<PsiElement>();

    PsiElement element = file.findElementAt(offset);
    if (element == null) {
      return PsiElement.EMPTY_ARRAY;
    }

    PsiElement topElement = element;
    element = element.getParent();

    while (element != null) {
      if (element.getTextRange().getStartOffset() == offset
          && element.getTextLength() <= patternLength) {
        topElement = element;
      }
      element = element.getParent();
    }

    if (topElement instanceof PsiFile) {
      return topElement.getChildren();
    }

    final int endOffset = offset + patternLength;
    result.add(topElement);
    topElement = topElement.getNextSibling();

    while (topElement != null && topElement.getTextRange().getEndOffset() <= endOffset) {
      result.add(topElement);
      topElement = topElement.getNextSibling();
    }

    return result.toArray(new PsiElement[result.size()]);
  }
Beispiel #2
0
    @Override
    public void visitElement(PsiElement element) {
      super.visitElement(element);

      final EquivalenceDescriptorProvider descriptorProvider =
          EquivalenceDescriptorProvider.getInstance(element);

      if (descriptorProvider != null) {
        final EquivalenceDescriptor descriptor1 = descriptorProvider.buildDescriptor(element);
        final EquivalenceDescriptor descriptor2 =
            descriptorProvider.buildDescriptor(myGlobalVisitor.getElement());

        if (descriptor1 != null && descriptor2 != null) {
          final boolean result =
              DuplocatorUtil.match(
                  descriptor1,
                  descriptor2,
                  myGlobalVisitor,
                  Collections.<PsiElementRole>emptySet(),
                  null);
          myGlobalVisitor.setResult(result);
          return;
        }
      }

      if (isLiteral(element)) {
        visitLiteral(element);
        return;
      }

      if (canBePatternVariable(element)
          && myGlobalVisitor.getMatchContext().getPattern().isRealTypedVar(element)
          && !shouldIgnoreVarNode(element)) {

        PsiElement matchedElement = myGlobalVisitor.getElement();
        PsiElement newElement = SkippingHandler.skipNodeIfNeccessary(matchedElement);
        while (newElement != matchedElement) {
          matchedElement = newElement;
          newElement = SkippingHandler.skipNodeIfNeccessary(matchedElement);
        }

        myGlobalVisitor.setResult(myGlobalVisitor.handleTypedElement(element, matchedElement));
      } else if (element instanceof LeafElement) {
        myGlobalVisitor.setResult(element.getText().equals(myGlobalVisitor.getElement().getText()));
      } else if (element.getFirstChild() == null && element.getTextLength() == 0) {
        myGlobalVisitor.setResult(true);
      } else {
        PsiElement patternChild = element.getFirstChild();
        PsiElement matchedChild = myGlobalVisitor.getElement().getFirstChild();

        FilteringNodeIterator patternIterator = new SsrFilteringNodeIterator(patternChild);
        FilteringNodeIterator matchedIterator = new SsrFilteringNodeIterator(matchedChild);

        boolean matched = myGlobalVisitor.matchSequentially(patternIterator, matchedIterator);
        myGlobalVisitor.setResult(matched);
      }
    }
Beispiel #3
0
 private static boolean isLiteral(PsiElement element) {
   if (element == null) return false;
   final ASTNode astNode = element.getNode();
   if (astNode == null) {
     return false;
   }
   final IElementType elementType = astNode.getElementType();
   final ParserDefinition parserDefinition =
       LanguageParserDefinitions.INSTANCE.forLanguage(element.getLanguage());
   if (parserDefinition != null) {
     final TokenSet literals = parserDefinition.getStringLiteralElements();
     return literals.contains(elementType);
   }
   return false;
 }
Beispiel #4
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];
  }
Beispiel #5
0
    private void doVisitElement(PsiElement element) {
      CompiledPattern pattern = myGlobalVisitor.getContext().getPattern();

      if (myGlobalVisitor.getCodeBlockLevel() == 0) {
        initTopLevelElement(element);
        return;
      }

      if (canBePatternVariable(element) && pattern.isRealTypedVar(element)) {
        myGlobalVisitor.handle(element);
        final MatchingHandler handler = pattern.getHandler(element);
        handler.setFilter(
            new NodeFilter() {
              public boolean accepts(PsiElement other) {
                return canBePatternVariableValue(other);
              }
            });

        super.visitElement(element);

        return;
      }

      super.visitElement(element);

      if (myGlobalVisitor.getContext().getSearchHelper().doOptimizing()
          && element instanceof LeafElement) {
        ParserDefinition parserDefinition =
            LanguageParserDefinitions.INSTANCE.forLanguage(element.getLanguage());
        if (parserDefinition != null) {
          String text = element.getText();

          // todo: support variables inside comments
          boolean flag = true;
          if (StringUtil.isJavaIdentifier(text) && flag) {
            myGlobalVisitor.processTokenizedName(
                text, true, GlobalCompilingVisitor.OccurenceKind.CODE);
          }
        }
      }
    }
Beispiel #6
0
    public void visitLiteral(PsiElement literal) {
      final PsiElement l2 = myGlobalVisitor.getElement();

      MatchingHandler handler = (MatchingHandler) literal.getUserData(CompiledPattern.HANDLER_KEY);

      if (handler instanceof SubstitutionHandler) {
        int offset = 0;
        int length = l2.getTextLength();
        final String text = l2.getText();

        if (length > 2 && (text.charAt(0) == '"' && text.charAt(length - 1) == '"')
            || (text.charAt(0) == '\'' && text.charAt(length - 1) == '\'')) {
          length--;
          offset++;
        }
        myGlobalVisitor.setResult(
            ((SubstitutionHandler) handler)
                .handle(l2, offset, length, myGlobalVisitor.getMatchContext()));
      } else if (handler != null) {
        myGlobalVisitor.setResult(handler.match(literal, l2, myGlobalVisitor.getMatchContext()));
      } else {
        myGlobalVisitor.setResult(literal.textMatches(l2));
      }
    }
Beispiel #7
0
    private void visitLiteral(PsiElement literal) {
      String value = literal.getText();

      if (value.length() > 2 && (value.charAt(0) == '"' && value.charAt(value.length() - 1) == '"')
          || (value.charAt(0) == '\'' && value.charAt(value.length() - 1) == '\'')) {

        if (mySubstitutionPatterns == null) {
          final String[] prefixes = myGlobalVisitor.getContext().getPattern().getTypedVarPrefixes();
          mySubstitutionPatterns = createPatterns(prefixes);
        }

        for (Pattern substitutionPattern : mySubstitutionPatterns) {
          @Nullable
          MatchingHandler handler =
              myGlobalVisitor.processPatternStringWithFragments(
                  value, GlobalCompilingVisitor.OccurenceKind.LITERAL, substitutionPattern);

          if (handler != null) {
            literal.putUserData(CompiledPattern.HANDLER_KEY, handler);
            break;
          }
        }
      }
    }
Beispiel #8
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];
  }
Beispiel #9
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)));
      }
    }
Beispiel #10
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);
              }
            });
  }
Beispiel #11
0
 @Override
 public boolean canBeVarDelimeter(@NotNull PsiElement element) {
   final ASTNode node = element.getNode();
   return node != null && getVariableDelimiters().contains(node.getElementType());
 }
Beispiel #12
0
 private static boolean canBePatternVariableValue(PsiElement element) {
   // can be leaf element! (ex. var a = 1 <-> var $a$ = 1)
   return !containsOnlyDelimeters(element.getText());
 }