package krasa.languageSupport; import java.util.Collection; import java.util.Collections; import java.util.Set; import org.jetbrains.annotations.NotNull; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleUtilCore; import com.intellij.openapi.roots.ModuleRootManager; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.TextRange; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.patterns.PlatformPatterns; import com.intellij.patterns.PsiJavaPatterns; import com.intellij.patterns.StandardPatterns; import com.intellij.patterns.VirtualFilePattern; import com.intellij.psi.*; import com.intellij.psi.impl.source.resolve.reference.impl.providers.FilePathReferenceProvider; 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.impl.source.tree.java.PsiLiteralExpressionImpl; import com.intellij.psi.impl.source.tree.java.PsiMethodCallExpressionImpl; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.containers.ContainerUtil; public class IntegrationTestFileReferenceContributor extends PsiReferenceContributor { private final boolean myEndingSlashNotAllowed = true; static final VirtualFilePattern IN_IT = PsiJavaPatterns.virtualFile() .withName(StandardPatterns.string().endsWith("IT.java")); @Override public void registerReferenceProviders(@NotNull PsiReferenceRegistrar psiReferenceRegistrar) { MyFilePathReferenceProvider provider = new MyFilePathReferenceProvider(); psiReferenceRegistrar.registerReferenceProvider( PlatformPatterns.psiElement(PsiLiteralExpression.class).inVirtualFile(IN_IT), provider); // psiReferenceRegistrar.registerReferenceProvider(PlatformPatterns.psiElement(PsiReferenceExpression.class).inVirtualFile(inIT), // provider, PsiReferenceRegistrar.HIGHER_PRIORITY); } private class MyFilePathReferenceProvider extends FilePathReferenceProvider { @NotNull public PsiReference[] getReferencesByElement(@NotNull PsiElement element, String text, int offset, final boolean soft, @NotNull final Module... forModules) { return new MyFileReferenceSet(text, element, offset, soft, forModules).getAllReferences(); } private class MyFileReferenceSet extends FileReferenceSet { private final boolean soft; private final Module[] forModules; public MyFileReferenceSet(String text, PsiElement element, int offset, boolean soft, Module... forModules) { super(text, element, offset, MyFilePathReferenceProvider.this, true, myEndingSlashNotAllowed); this.soft = soft; this.forModules = forModules; } @Override protected boolean isSoft() { return soft; } @Override public boolean isAbsolutePathReference() { return true; } @Override public boolean couldBeConvertedTo(boolean relative) { return !relative; } @Override public boolean absoluteUrlNeedsStartSlash() { final String s = getPathString(); return s != null && !s.isEmpty() && s.charAt(0) == '/'; } @Override @NotNull public Collection<PsiFileSystemItem> computeDefaultContexts() { PsiMethodCallExpressionImpl inMethod = PsiTreeUtil.getParentOfType(getElement(), PsiMethodCallExpressionImpl.class); boolean isRequest = false; boolean isResponse = false; boolean isFolderName = false; boolean expectCallAndReturn = false; String folderNameStr = null; if (inMethod != null) { PsiMethod psiMethod = inMethod.resolveMethod(); if (psiMethod != null) { String methodName = psiMethod.getName(); if ("request".equals(methodName)) { folderNameStr = resolveFolderNameFromFluentCall(inMethod); isRequest = true; } else if ("response".equals(methodName)) { folderNameStr = resolveFolderNameFromFluentCall(inMethod); isResponse = true; } else if ("expectCallAndReturn".equals(methodName)) { expectCallAndReturn = true; } else if ("folderName".equals(methodName) || "expectCall".equals(methodName)) { isFolderName = true; } } } if (!isRequest && !isResponse && !isFolderName && !expectCallAndReturn) { return Collections.emptyList(); } if (forModules.length > 0) { Set<PsiFileSystemItem> rootsForModules = ContainerUtil.newLinkedHashSet(); for (Module forModule : forModules) { rootsForModules.addAll(getRoots(forModule, true)); } return rootsForModules; } Module thisModule = ModuleUtilCore.findModuleForPsiElement(getElement()); if (thisModule == null) return Collections.emptyList(); ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(thisModule); Collection<PsiFileSystemItem> roots = getRoots(thisModule, true); VirtualFile[] sourceRoots = moduleRootManager.orderEntries().recursively().withoutSdk() .withoutLibraries().sources().usingCache().getRoots(); final PsiManager psiManager = PsiManager.getInstance(thisModule.getProject()); for (VirtualFile root : sourceRoots) { final PsiDirectory directory = psiManager.findDirectory(root); if (directory != null) { if (isRequest) { PsiDirectory subdirectory = directory.findSubdirectory("dummy-requests"); if (subdirectory != null) { roots.add(subdirectory); } if (subdirectory != null && folderNameStr != null) { subdirectory = subdirectory.findSubdirectory(folderNameStr); if (subdirectory != null) { roots.add(subdirectory); } } } else if (isResponse) { PsiDirectory subdirectory = directory.findSubdirectory("dummy-responses"); if (subdirectory != null && folderNameStr != null) { subdirectory = subdirectory.findSubdirectory(folderNameStr); if (subdirectory != null) { roots.add(subdirectory); } } } else if (expectCallAndReturn) { PsiDirectory subdirectory = directory.findSubdirectory("dummy-responses"); if (subdirectory != null) { roots.add(subdirectory); } // nejde prijit na to kde je fokus // subdirectory = // directory.findSubdirectory("dummy-requests"); // if (subdirectory != null) { // roots.add(subdirectory); // } } else if (isFolderName) { PsiDirectory subdirectory = directory.findSubdirectory("dummy-responses"); if (subdirectory != null) { roots.add(subdirectory); } subdirectory = directory.findSubdirectory("dummy-requests"); if (subdirectory != null) { roots.add(subdirectory); } } } } return roots; } @Override public FileReference createFileReference(final TextRange range, final int index, final String text) { // System.err.println(new StringBuilder().append( // index).append(text).toString()); return MyFilePathReferenceProvider.this.createFileReference(this, range, index, text); } @Override protected Condition<PsiFileSystemItem> getReferenceCompletionFilter() { return element1 -> isPsiElementAccepted(element1); } } } public static String resolveFolderNameFromFluentCall(PsiMethodCallExpressionImpl parentOfType) { String folderNameStr = null; Collection<PsiMethodCallExpressionImpl> childrenOfAnyType = PsiTreeUtil.findChildrenOfType(parentOfType, PsiMethodCallExpressionImpl.class); for (PsiMethodCallExpressionImpl previousFluentMethod : childrenOfAnyType) { if (previousFluentMethod != null) { PsiMethod psiMethod = previousFluentMethod.resolveMethod(); if (psiMethod != null) { if ("folderName".equals(psiMethod.getName()) || "expectCall".equals(psiMethod.getName())) { PsiLiteralExpressionImpl folderNameExp = PsiTreeUtil.findChildOfType(previousFluentMethod, PsiLiteralExpressionImpl.class); if (folderNameExp != null) { folderNameStr = folderNameExp.getInnerText(); } } else if ("expectCallAndReturn".equals(psiMethod.getName())) { PsiLiteralExpressionImpl folderNameExp = PsiTreeUtil.findChildOfType(previousFluentMethod, PsiLiteralExpressionImpl.class); if (folderNameExp != null) { String innerText = folderNameExp.getInnerText(); if (innerText != null) { String[] split = innerText.split("/"); if (split.length == 2) { folderNameStr = split[0]; } } } } } } } return folderNameStr; } }