/*
* 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;
import com.goide.psi.GoStatement;
import com.goide.sdk.GoSdkService;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.testFramework.exceptionCases.AssertionErrorCase;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.List;
import static com.intellij.util.containers.ContainerUtil.newArrayList;
@SdkAware
public class GoFindUsageTest extends GoCodeInsightFixtureTestCase {
private static final String USAGE = "/*usage*/";
private void doTest(@NotNull String text) {
List<Integer> offsets = allOccurrences(StringUtil.replace(text, "<caret>", ""), USAGE);
String replace = StringUtil.replace(text, USAGE, "");
myFixture.configureByText("a.go", replace);
PsiElement atCaret = myFixture.getElementAtCaret();
List<Integer> actual = ContainerUtil.map(myFixture.findUsages(atCaret), UsageInfo::getNavigationOffset);
assertSameElements(actual, offsets);
}
@NotNull
private static List<Integer> allOccurrences(@NotNull String text, @NotNull String what) {
List<Integer> list = newArrayList();
int index = text.indexOf(what);
while (index >= 0) {
list.add(index - list.size() * what.length());
index = text.indexOf(what, index + 1);
}
return list;
}
public void testBuiltinHighlighting() {
myFixture.configureByText("a.go", "package main; func bar() i<caret>nt {}");
assertSize(1, myFixture.findUsages(myFixture.getElementAtCaret()));
}
// #2301
public void testCheckImportInWholePackage() {
myFixture.addFileToProject("bar/bar1.go", "package bar; func Bar() { b := bar{}; b.f.Method() }");
myFixture.addFileToProject("bar/bar.go", "package bar; import \"foo\"; type bar struct { f *foo.Foo }");
PsiFile file = myFixture.addFileToProject("foo/foo.go", "package foo; type Foo struct{}; func (*Foo) M<caret>ethod() {}");
myFixture.configureFromExistingVirtualFile(file.getVirtualFile());
Collection<UsageInfo> usages = myFixture.findUsages(myFixture.getElementAtCaret());
assertSize(1, usages);
UsageInfo first = usages.iterator().next();
PsiElement e = first.getElement();
GoStatement statement = PsiTreeUtil.getParentOfType(e, GoStatement.class);
assertNotNull(statement);
assertEquals("b.f.Method()", statement.getText());
}
public void testCheckImportInWholePackageWithRelativeImports() {
myFixture.addFileToProject("bar/bar1.go", "package bar; func Bar() { b := bar{}; b.f.Method() }");
myFixture.addFileToProject("bar/bar.go", "package bar; import \"..\"; type bar struct { f *foo.Foo }");
myFixture.configureByText("foo.go", "package foo; type Foo struct{}; func (*Foo) M<caret>ethod() {}");
assertSize(1, myFixture.findUsages(myFixture.getElementAtCaret()));
}
public void testOverride() {
doTest("package p\n" +
"func test2() {\n" +
" y := 1\n" +
" {\n" +
" <caret>y, _ := 10, 1\n" +
" fmt.Println(/*usage*/y)\n" +
" }\n" +
"}\n");
}
public void testOverride1() {
doTest("package p\n" +
"func test2() {\n" +
" <caret>y := 1\n" +
" /*usage*/y, _ := 10, 1\n" +
" /*usage*/y, x := 10, 1\n" +
" fmt.Println(/*usage*/y)\n" +
"}\n");
}
public void testOverride2() {
doTest("package p\n" +
"func test2() {\n" +
" <caret>y := 1\n" +
" {\n" +
" y, _ := 10, 1\n" +
" fmt.Println(y)\n" +
" }\n" +
"}\n");
}
public void testFunctionParam() {
doTest("package p\n" +
"func aaa(<caret>a int) {\n" +
" /*usage*/a\n" +
" var a int\n" +
" a := 1\n" +
"}\n");
}
public void testDeclaredInForRange() {
doTest("package main\n" +
"const key = iota\n" +
"func main() {\n" +
" key := 1\n" +
" for <caret>key, val := range m {\n" +
" y := /*usage*/key\n" +
" }\n" +
"}");
}
public void testMethodWithTransitiveImport() {
myFixture.addFileToProject("a.go", "package main; import `middle`; func main() { fmt.Println(middle.A.Method()) }");
myFixture.addFileToProject("middle/middle.go", "package middle; import `declaration`; var A *declaration.D = nil");
PsiFile file =
myFixture.addFileToProject("declaration/declaration.go", "package declaration; type D struct {}; func (D) Met<caret>hod() {}");
myFixture.configureFromExistingVirtualFile(file.getVirtualFile());
Collection<UsageInfo> usages = myFixture.findUsages(myFixture.getElementAtCaret());
assertEquals(1, usages.size());
//noinspection ConstantConditions
assertEquals("a.go", usages.iterator().next().getFile().getName());
}
public void testDoNoLoadUnreachableVendorDirectory() {
myFixture.addFileToProject("a.go", "package a; import `foo/vendor/foo`; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/vendor/foo/foo.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
myFixture.findUsages(myFixture.getElementAtCaret());
}
public void testDoNoLoadUnreachableInternalDirectory() {
GoSdkService.setTestingSdkVersion("1.5", getTestRootDisposable());
myFixture.addFileToProject("a.go", "package a; import `foo/internal/foo`; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/internal/foo/foo.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
myFixture.findUsages(myFixture.getElementAtCaret());
}
public void testDoNoLoadNotImportedDirectory() {
myFixture.addFileToProject("bar/bar.go", "package bar; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/foo.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
myFixture.findUsages(myFixture.getElementAtCaret());
}
public void testDoNoLoadTestDirectoryFromTestFileWithDifferentPackage() {
myFixture.addFileToProject("bar/bar_test.go", "package bar; import `foo`; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/foo_test.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
myFixture.findUsages(myFixture.getElementAtCaret());
}
public void testDoNoLoadTestDirectoryFromProductionFile() {
myFixture.addFileToProject("bar/bar.go", "package bar; import `foo`; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/foo_test.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
myFixture.findUsages(myFixture.getElementAtCaret());
}
public void testLoadTestDirectoryFromTestFile() throws Throwable {
myFixture.addFileToProject("foo/bar_test.go", "package foo_test; import `foo`; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/foo_test.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
assertException(new AssertionErrorCase() {
@Override
public void tryClosure() {
try {
myFixture.findUsages(myFixture.getElementAtCaret());
}
catch (AssertionError e) {
String message = e.getMessage();
assertTrue(message.contains("Access to tree elements not allowed in tests"));
assertTrue(message.contains("bar_test.go"));
throw e;
}
}
});
}
public void testLoadSdkUsagesForSdkDeclarations() throws Throwable {
myFixture.configureByText("bar.go", "package foo; import `io`; type ReaderWrapper interface{io.Rea<caret>der}");
failOnFileLoading();
assertException(new AssertionErrorCase() {
@Override
public void tryClosure() {
try {
assertSize(5, myFixture.findUsages(myFixture.getElementAtCaret()));
}
catch (AssertionError e) {
String message = e.getMessage();
assertTrue(message.contains("Access to tree elements not allowed in tests"));
assertTrue(message.contains("io.go"));
throw e;
}
}
});
}
public void testDoNotLoadSdkUsagesForProjectDeclarations() {
myFixture.configureByText("foo.go", "package foo; func _() { Println() }");
myFixture.configureByText("bar.go", "package foo; func Pri<caret>ntln() {}");
failOnFileLoading();
assertSize(1, myFixture.findUsages(myFixture.getElementAtCaret()));
}
public void testLoadImportedDirectory() throws Throwable {
myFixture.addFileToProject("bar/bar.go", "package bar; import `foo`; func _() { println(CONST_NAME) }");
PsiFile declarationFile = myFixture.addFileToProject("foo/foo.go", "package foo; const CON<caret>ST_NAME = 1;");
myFixture.configureFromExistingVirtualFile(declarationFile.getVirtualFile());
failOnFileLoading();
assertException(new AssertionErrorCase() {
@Override
public void tryClosure() {
try {
assertSize(1, myFixture.findUsages(myFixture.getElementAtCaret()));
}
catch (AssertionError e) {
String message = e.getMessage();
assertTrue(message.contains("Access to tree elements not allowed in tests"));
assertTrue(message.contains("bar.go"));
throw e;
}
}
});
}
public void testSdkTestDataDirectory() {
myFixture.configureByText("a.go", "package a; import `doc/testdata`; func _() { println(pkg.ExportedConst<caret>ant) } ");
PsiReference reference = myFixture.getFile().findReferenceAt(myFixture.getCaretOffset());
PsiElement resolve = reference != null ? reference.resolve() : null;
assertNotNull(resolve);
assertEquals("pkg.go", resolve.getContainingFile().getName());
assertEmpty(myFixture.findUsages(resolve));
}
private void failOnFileLoading() {
((PsiManagerImpl)myFixture.getPsiManager()).setAssertOnFileLoadingFilter(VirtualFileFilter.ALL, getTestRootDisposable());
}
private void doTestDoNotFind(@NotNull String text) {
myFixture.configureByText("a.go", text);
PsiElement atCaret = myFixture.getElementAtCaret();
try {
myFixture.findUsages(atCaret);
fail("Shouldn't be performed");
}
catch (AssertionError e) {
assertEquals("Cannot find handler for: IMPORT_SPEC", e.getMessage());
}
}
public void testDot() { doTestDoNotFind("package main; import <caret>. \"fmt\""); }
public void testUnderscore() { doTestDoNotFind("package main; import <caret>_ \"fmt\""); }
public void testNearImportString() { doTestDoNotFind("package main; import <caret>\"fmt\""); }
}