/*
* Copyright 2013-2016 Sergey Ignatov, Alexander Zolotov, Florin Patan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.goide.psi.impl.imports;
import com.goide.codeInsight.imports.GoGetPackageFix;
import com.goide.completion.GoCompletionUtil;
import com.goide.quickfix.GoDeleteImportQuickFix;
import com.goide.sdk.GoPackageUtil;
import com.intellij.codeInsight.completion.CompletionUtil;
import com.intellij.codeInsight.daemon.quickFix.CreateFileFix;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.openapi.util.TextRange;
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.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.Set;
public class GoImportReference extends FileReference {
public GoImportReference(@NotNull FileReferenceSet fileReferenceSet, TextRange range, int index, String text) {
super(fileReferenceSet, range, index, text);
}
@Override
protected Object createLookupItem(PsiElement candidate) {
if (candidate instanceof PsiDirectory) {
return GoCompletionUtil.createDirectoryLookupElement((PsiDirectory)candidate);
}
return super.createLookupItem(candidate);
}
@NotNull
@Override
protected ResolveResult[] innerResolve(boolean caseSensitive, @NotNull PsiFile file) {
if (isFirst()) {
if (".".equals(getCanonicalText())) {
PsiDirectory directory = getDirectory();
return directory != null ? new PsiElementResolveResult[]{new PsiElementResolveResult(directory)} : ResolveResult.EMPTY_ARRAY;
}
else if ("..".equals(getCanonicalText())) {
PsiDirectory directory = getDirectory();
PsiDirectory grandParent = directory != null ? directory.getParentDirectory() : null;
return grandParent != null ? new PsiElementResolveResult[]{new PsiElementResolveResult(grandParent)} : ResolveResult.EMPTY_ARRAY;
}
}
String referenceText = getText();
Set<ResolveResult> result = ContainerUtil.newLinkedHashSet();
Set<ResolveResult> innerResult = ContainerUtil.newLinkedHashSet();
for (PsiFileSystemItem context : getContexts()) {
innerResolveInContext(referenceText, context, innerResult, caseSensitive);
for (ResolveResult resolveResult : innerResult) {
PsiElement element = resolveResult.getElement();
if (element instanceof PsiDirectory) {
if (isLast()) {
return new ResolveResult[]{resolveResult};
}
result.add(resolveResult);
}
}
innerResult.clear();
}
return result.isEmpty() ? ResolveResult.EMPTY_ARRAY : result.toArray(new ResolveResult[result.size()]);
}
@Override
public boolean isReferenceTo(PsiElement element) {
if (super.isReferenceTo(element)) {
return true;
}
if (element instanceof PsiDirectoryContainer) {
for (PsiDirectory directory : ((PsiDirectoryContainer)element).getDirectories()) {
if (super.isReferenceTo(directory)) {
return true;
}
}
}
return false;
}
@Override
public PsiElement bindToElement(@NotNull PsiElement element, boolean absolute) throws IncorrectOperationException {
if (!absolute) {
FileReference firstReference = ArrayUtil.getFirstElement(getFileReferenceSet().getAllReferences());
if (firstReference != null) {
Collection<PsiFileSystemItem> contexts = getFileReferenceSet().getDefaultContexts();
for (ResolveResult resolveResult : firstReference.multiResolve(false)) {
PsiElement resolveResultElement = resolveResult.getElement();
if (resolveResultElement instanceof PsiFileSystemItem) {
PsiFileSystemItem parentDirectory = ((PsiFileSystemItem)resolveResultElement).getParent();
if (parentDirectory != null && contexts.contains(parentDirectory)) {
return getElement();
}
}
}
}
}
return super.bindToElement(element, absolute);
}
@Override
public LocalQuickFix[] getQuickFixes() {
if (GoPackageUtil.isBuiltinPackage(resolve())) {
return new LocalQuickFix[]{new GoDeleteImportQuickFix()};
}
List<LocalQuickFix> result = ContainerUtil.newArrayList();
FileReferenceSet fileReferenceSet = getFileReferenceSet();
if (fileReferenceSet instanceof GoImportReferenceSet && !((GoImportReferenceSet)fileReferenceSet).isRelativeImport()
&& !fileReferenceSet.isAbsolutePathReference()) {
result.add(new GoGetPackageFix(fileReferenceSet.getPathString()));
}
String fileNameToCreate = getFileNameToCreate();
for (PsiFileSystemItem context : getContexts()) {
if (context instanceof PsiDirectory) {
try {
((PsiDirectory)context).checkCreateSubdirectory(fileNameToCreate);
String targetPath = context.getVirtualFile().getPath();
result.add(new CreateFileFix(true, fileNameToCreate, (PsiDirectory)context) {
@NotNull
@Override
public String getText() {
return "Create Directory " + fileNameToCreate + " at " + targetPath;
}
});
}
catch (IncorrectOperationException ignore) {
}
}
}
return result.toArray(new LocalQuickFix[result.size()]);
}
private boolean isFirst() {
return getIndex() <= 0;
}
@Nullable
private PsiDirectory getDirectory() {
PsiElement originalElement = CompletionUtil.getOriginalElement(getElement());
PsiFile file = originalElement != null ? originalElement.getContainingFile() : getElement().getContainingFile();
return file.getParent();
}
}