Package com.jetbrains.lang.dart.psi.impl

Source Code of com.jetbrains.lang.dart.psi.impl.DartFileReferenceImpl

package com.jetbrains.lang.dart.psi.impl;

import com.intellij.lang.ASTNode;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReference;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.FileReferenceSet;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import com.jetbrains.lang.dart.psi.DartPartStatement;
import com.jetbrains.lang.dart.psi.DartPathOrLibraryReference;
import com.jetbrains.lang.dart.psi.DartReference;
import com.jetbrains.lang.dart.psi.DartStringLiteralExpression;
import com.jetbrains.lang.dart.util.DartClassResolveResult;
import com.jetbrains.lang.dart.util.DartElementGenerator;
import com.jetbrains.lang.dart.util.DartResolveUtil;
import com.jetbrains.lang.dart.util.DartUrlResolver;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.Collection;

import static com.jetbrains.lang.dart.util.DartUrlResolver.DART_PREFIX;
import static com.jetbrains.lang.dart.util.DartUrlResolver.FILE_PREFIX;
import static com.jetbrains.lang.dart.util.DartUrlResolver.PACKAGE_PREFIX;

public class DartFileReferenceImpl extends DartExpressionImpl implements DartReference, PsiPolyVariantReference {
  public DartFileReferenceImpl(ASTNode node) {
    super(node);
  }

  @Override
  public PsiElement getElement() {
    return this;
  }

  @Override
  public PsiReference getReference() {
    return this;
  }

  @Override
  public TextRange getRangeInElement() {
    final TextRange textRange = getTextRange();
    return new TextRange(0, textRange.getEndOffset() - textRange.getStartOffset());
  }

  @NotNull
  @Override
  public String getCanonicalText() {
    return getText();
  }

  @Override
  public PsiElement handleElementRename(String newElementName) throws IncorrectOperationException {
    setNewPath(getNewPath(newElementName));
    return this;
  }

  private void setNewPath(String newPath) {
    final DartPartStatement sourceStatement =
      DartElementGenerator.createPartStatementFromPath(getProject(), newPath);
    final DartPathOrLibraryReference newPathReference = sourceStatement == null ? null : sourceStatement.getPathOrLibraryReference();
    final DartStringLiteralExpression myStringLiteralExpression = PsiTreeUtil.getChildOfType(this, DartStringLiteralExpression.class);
    if (newPathReference != null && myStringLiteralExpression != null) {
      getNode().replaceChild(myStringLiteralExpression.getNode(), newPathReference.getStringLiteralExpression().getNode());
    }
  }

  private String getNewPath(String name) {
    final String path = StringUtil.unquoteString(getText());
    final int index = Math.max(path.lastIndexOf('\\'), path.lastIndexOf('/'));
    return index == -1 ? name : path.substring(0, index + 1) + name;
  }

  @Override
  public PsiElement bindToElement(@NotNull PsiElement element) throws IncorrectOperationException {
    final VirtualFile virtualFile = DartResolveUtil.getRealVirtualFile(getContainingFile());
    final VirtualFile parentFolder = virtualFile == null ? null : virtualFile.getParent();
    final VirtualFile destinationVirtualFile = DartResolveUtil.getRealVirtualFile(element.getContainingFile());
    if (parentFolder != null && destinationVirtualFile != null) {
      setNewPath(FileUtil.getRelativePath(parentFolder.getPath(), destinationVirtualFile.getPath(), '/'));
    }
    return this;
  }

  @Override
  public boolean isReferenceTo(PsiElement element) {
    return resolve() == element;
  }

  @NotNull
  @Override
  public Object[] getVariants() {
    // DartLibraryNameCompletionContributor
    return ArrayUtil.EMPTY_OBJECT_ARRAY;
  }

  @Override
  public boolean isSoft() {
    return false;
  }

  @Override
  public PsiElement resolve() {
    final ResolveResult[] resolveResults = multiResolve(true);

    return resolveResults.length == 0 ||
           resolveResults.length > 1 ||
           !resolveResults[0].isValidResult() ? null : resolveResults[0].getElement();
  }

  @NotNull
  @Override
  public DartClassResolveResult resolveDartClass() {
    return DartClassResolveResult.EMPTY;
  }

  @NotNull
  @Override
  public ResolveResult[] multiResolve(boolean incompleteCode) {
    final PsiFile psiFile = getContainingFile();
    final VirtualFile virtualFile = DartResolveUtil.getRealVirtualFile(psiFile);
    if (virtualFile == null) return ResolveResult.EMPTY_ARRAY;

    final String text = StringUtil.unquoteString(getText());
    final VirtualFile result = text.startsWith(PACKAGE_PREFIX) || text.startsWith(DART_PREFIX) || text.startsWith(FILE_PREFIX)
                               ? DartUrlResolver.getInstance(getProject(), virtualFile).findFileByDartUrl(text)
                               : VfsUtilCore.findRelativeFile(text, virtualFile);

    final PsiFile sourcePsiFile = result == null ? null : getManager().findFile(result);
    return sourcePsiFile == null ? ResolveResult.EMPTY_ARRAY : new ResolveResult[]{new PsiElementResolveResult(sourcePsiFile)};
  }

  @NotNull
  @Override
  public PsiReference[] getReferences() {
    final String url = StringUtil.unquoteString(getText());
    if (url.startsWith(PACKAGE_PREFIX)) {
      final VirtualFile file = DartResolveUtil.getRealVirtualFile(getContainingFile());
      if (file == null) return PsiReference.EMPTY_ARRAY;

      final DartUrlResolver dartUrlResolver = DartUrlResolver.getInstance(getProject(), file);

      final int slashIndex = url.indexOf('/');
      if (slashIndex > 0) {
        final String packageName = url.substring(PACKAGE_PREFIX.length(), slashIndex);
        final VirtualFile packageDir = dartUrlResolver.getPackageDirIfLivePackageOrFromPubListPackageDirs(packageName);
        if (packageDir != null) {
          return getPackageReferences(file, packageDir, url.substring(slashIndex + 1), slashIndex + 1);
        }
      }

      final String relPath = url.substring(PACKAGE_PREFIX.length());
      final VirtualFile[] packageRoots = dartUrlResolver.getPackageRoots();

      if (packageRoots.length == 0) return PsiReference.EMPTY_ARRAY;
      if (packageRoots.length == 1) return getPackageReferences(file, packageRoots[0], relPath, PACKAGE_PREFIX.length());

      final Collection<PsiReference> result = new SmartList<PsiReference>();
      for (VirtualFile packageRoot : packageRoots) {
        if (packageRoot.findFileByRelativePath(relPath) != null) {
          ContainerUtil.addAll(result, getPackageReferences(file, packageRoot, relPath, PACKAGE_PREFIX.length()));
        }
      }

      return result.toArray(new PsiReference[result.size()]);
    }

    final FileReferenceSet referenceSet = new FileReferenceSet(url, this, 1, null, false, true);
    return ArrayUtil.mergeArrays(super.getReferences(), referenceSet.getAllReferences());
  }

  @NotNull
  private PsiReference[] getPackageReferences(final @NotNull VirtualFile contextFile,
                                              final @Nullable VirtualFile packagesFolder,
                                              final @NotNull String relPathFromPackagesFolderToReferencedFile,
                                              final int startIndex) {
    final VirtualFile parentFile = contextFile.getParent();
    if (packagesFolder == null || parentFile == null) return PsiReference.EMPTY_ARRAY;

    String relPathFromContextFileToPackagesFolder = FileUtil.getRelativePath(parentFile.getPath(), packagesFolder.getPath(), '/');
    if (relPathFromContextFileToPackagesFolder == null) return PsiReference.EMPTY_ARRAY;

    relPathFromContextFileToPackagesFolder += "/";
    final FileReferenceSet referenceSet =
      new FileReferenceSet(relPathFromContextFileToPackagesFolder + relPathFromPackagesFolderToReferencedFile, this, 0, null, false, true);
    final FileReference[] references = referenceSet.getAllReferences();

    final int nestedLevel = StringUtil.countChars(relPathFromContextFileToPackagesFolder, '/');
    final int shift = startIndex - relPathFromContextFileToPackagesFolder.length() + 1;
    return references.length < nestedLevel ?
           PsiReference.EMPTY_ARRAY :
           shiftReferences(Arrays.copyOfRange(references, nestedLevel, references.length), shift);
  }

  private static FileReference[] shiftReferences(FileReference[] references, final int shift) {
    return ContainerUtil.map(references, new Function<FileReference, FileReference>() {
      @Override
      public FileReference fun(FileReference reference) {
        return new FileReference(
          reference.getFileReferenceSet(),
          reference.getRangeInElement().shiftRight(shift),
          reference.getIndex(),
          reference.getText()
        );
      }
    }, FileReference.EMPTY);
  }

  public static class DartPathOrLibraryManipulator implements ElementManipulator<DartPathOrLibraryReference> {
    @Override
    public DartPathOrLibraryReference handleContentChange(@NotNull DartPathOrLibraryReference element,
                                                          @NotNull TextRange range,
                                                          String newContent)
      throws IncorrectOperationException {
      return element;
    }

    @Override
    public DartPathOrLibraryReference handleContentChange(@NotNull DartPathOrLibraryReference element, String newContent)
      throws IncorrectOperationException {
      return element;
    }

    @NotNull
    @Override
    public TextRange getRangeInElement(@NotNull DartPathOrLibraryReference element) {
      return element.getTextRange();
    }
  }
}
TOP

Related Classes of com.jetbrains.lang.dart.psi.impl.DartFileReferenceImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.