mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -17,6 +17,7 @@ package com.intellij.core;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
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.*;
|
||||
@@ -83,7 +84,7 @@ public class CoreJavaFileManager implements JavaFileManager {
|
||||
@Override
|
||||
public PsiClass findClass(@NotNull String qName, @NotNull GlobalSearchScope scope) {
|
||||
for (VirtualFile root : roots()) {
|
||||
final PsiClass psiClass = findClassInClasspathRoot(qName, root, myPsiManager);
|
||||
final PsiClass psiClass = findClassInClasspathRoot(qName, root, myPsiManager, scope);
|
||||
if (psiClass != null) {
|
||||
return psiClass;
|
||||
}
|
||||
@@ -92,7 +93,10 @@ public class CoreJavaFileManager implements JavaFileManager {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static PsiClass findClassInClasspathRoot(String qName, VirtualFile root, PsiManager psiManager) {
|
||||
public static PsiClass findClassInClasspathRoot(@NotNull String qName,
|
||||
@NotNull VirtualFile root,
|
||||
@NotNull PsiManager psiManager,
|
||||
@NotNull GlobalSearchScope scope) {
|
||||
String pathRest = qName;
|
||||
VirtualFile cur = root;
|
||||
|
||||
@@ -108,77 +112,73 @@ public class CoreJavaFileManager implements JavaFileManager {
|
||||
cur = child;
|
||||
}
|
||||
|
||||
String className = pathRest.replace('.', '$');
|
||||
int bucks = className.indexOf('$');
|
||||
String classNameWithInnerClasses = pathRest;
|
||||
String topLevelClassName = substringBeforeFirstDot(classNameWithInnerClasses);
|
||||
|
||||
String rootClassName;
|
||||
if (bucks < 0) {
|
||||
rootClassName = className;
|
||||
VirtualFile vFile = cur.findChild(topLevelClassName + ".class");
|
||||
if (vFile == null) vFile = cur.findChild(topLevelClassName + ".java");
|
||||
|
||||
if (vFile == null) {
|
||||
return null;
|
||||
}
|
||||
if (!vFile.isValid()) {
|
||||
LOG.error("Invalid child of valid parent: " + vFile.getPath() + "; " + root.isValid() + " path=" + root.getPath());
|
||||
return null;
|
||||
}
|
||||
if (!scope.contains(vFile)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiFile file = psiManager.findFile(vFile);
|
||||
if (!(file instanceof PsiClassOwner)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return findClassInPsiFile(classNameWithInnerClasses, (PsiClassOwner)file);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String substringBeforeFirstDot(@NotNull String classNameWithInnerClasses) {
|
||||
int dot = classNameWithInnerClasses.indexOf('.');
|
||||
if (dot < 0) {
|
||||
return classNameWithInnerClasses;
|
||||
}
|
||||
else {
|
||||
rootClassName = className.substring(0, bucks);
|
||||
className = className.substring(bucks + 1);
|
||||
return classNameWithInnerClasses.substring(0, dot);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass findClassInPsiFile(@NotNull String classNameWithInnerClassesDotSeparated, @NotNull PsiClassOwner file) {
|
||||
for (PsiClass topLevelClass : file.getClasses()) {
|
||||
PsiClass candidate = findClassByTopLevelClass(classNameWithInnerClassesDotSeparated, topLevelClass);
|
||||
if (candidate != null) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClass findClassByTopLevelClass(@NotNull String className, @NotNull PsiClass topLevelClass) {
|
||||
if (className.indexOf('.') < 0) {
|
||||
return className.equals(topLevelClass.getName()) ? topLevelClass : null;
|
||||
}
|
||||
|
||||
VirtualFile vFile = cur.findChild(rootClassName + ".class");
|
||||
if (vFile == null) vFile = cur.findChild(rootClassName + ".java");
|
||||
|
||||
if (vFile != null) {
|
||||
if (!vFile.isValid()) {
|
||||
LOG.error("Invalid child of valid parent: " + vFile.getPath() + "; " + root.isValid() + " path=" + root.getPath());
|
||||
Iterator<String> segments = StringUtil.split(className, ".").iterator();
|
||||
if (!segments.hasNext() || !segments.next().equals(topLevelClass.getName())) {
|
||||
return null;
|
||||
}
|
||||
PsiClass curClass = topLevelClass;
|
||||
while (segments.hasNext()) {
|
||||
String innerClassName = segments.next();
|
||||
PsiClass innerClass = curClass.findInnerClassByName(innerClassName, false);
|
||||
if (innerClass == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final PsiFile file = psiManager.findFile(vFile);
|
||||
if (file instanceof PsiClassOwner) {
|
||||
final PsiClass[] classes = ((PsiClassOwner)file).getClasses();
|
||||
if (classes.length == 1) {
|
||||
PsiClass curClass = classes[0];
|
||||
|
||||
if (bucks > 0) {
|
||||
Stack<ClassAndOffsets> currentPath = new Stack<ClassAndOffsets>();
|
||||
currentPath.add(new ClassAndOffsets(curClass, 0, 0));
|
||||
currentPath.add(currentPath.peek());
|
||||
|
||||
while (currentPath.size() > 1) {
|
||||
ClassAndOffsets classAndOffset = currentPath.pop();
|
||||
int newComponentStart = classAndOffset.componentStart;
|
||||
int lookupStart = classAndOffset.lookupStart;
|
||||
curClass = currentPath.peek().clazz; //owner class
|
||||
|
||||
while (lookupStart <= className.length()) {
|
||||
int bucksIndex = className.indexOf("$", lookupStart);
|
||||
bucksIndex = bucksIndex < 0 ? className.length(): bucksIndex;
|
||||
|
||||
String component = className.substring(newComponentStart, bucksIndex);
|
||||
PsiClass inner = curClass.findInnerClassByName(component, false);
|
||||
|
||||
lookupStart = bucksIndex + 1;
|
||||
if (inner == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
currentPath.add(new ClassAndOffsets(inner, newComponentStart, lookupStart));
|
||||
|
||||
newComponentStart = lookupStart;
|
||||
curClass = inner;
|
||||
}
|
||||
|
||||
if (lookupStart == newComponentStart) {
|
||||
return curClass;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
} else {
|
||||
return curClass;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
curClass = innerClass;
|
||||
}
|
||||
return curClass;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -186,7 +186,7 @@ public class CoreJavaFileManager implements JavaFileManager {
|
||||
public PsiClass[] findClasses(@NotNull String qName, @NotNull GlobalSearchScope scope) {
|
||||
List<PsiClass> result = new ArrayList<PsiClass>();
|
||||
for (VirtualFile file : roots()) {
|
||||
final PsiClass psiClass = findClassInClasspathRoot(qName, file, myPsiManager);
|
||||
final PsiClass psiClass = findClassInClasspathRoot(qName, file, myPsiManager, scope);
|
||||
if (psiClass != null) {
|
||||
result.add(psiClass);
|
||||
}
|
||||
@@ -203,17 +203,4 @@ public class CoreJavaFileManager implements JavaFileManager {
|
||||
public void addToClasspath(VirtualFile root) {
|
||||
myClasspath.add(root);
|
||||
}
|
||||
|
||||
private static class ClassAndOffsets {
|
||||
|
||||
final PsiClass clazz;
|
||||
final int componentStart;
|
||||
final int lookupStart;
|
||||
|
||||
ClassAndOffsets(PsiClass clazz, int componentStart, int lookupStart) {
|
||||
this.clazz = clazz;
|
||||
this.componentStart = componentStart;
|
||||
this.lookupStart = lookupStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,143 +21,186 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.testFramework.PsiTestCase;
|
||||
import com.intellij.testFramework.PsiTestUtil;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import org.intellij.lang.annotations.Language;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
|
||||
public class CoreJavaFileManagerTest extends PsiTestCase {
|
||||
|
||||
private VirtualFile prepareClasses(String clazzName, String clazzData) throws Exception {
|
||||
public void testCommon() throws Exception {
|
||||
CoreJavaFileManager manager = configureManager("package foo;\n\n" +
|
||||
"public class TopLevel {\n" +
|
||||
"public class Inner {\n" +
|
||||
" public class Inner {}\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"}", "TopLevel");
|
||||
|
||||
assertCanFind(manager, "foo.TopLevel");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner.Inner");
|
||||
|
||||
assertCannotFind(manager, "foo.TopLevel$Inner.Inner");
|
||||
assertCannotFind(manager, "foo.TopLevel.Inner$Inner");
|
||||
assertCannotFind(manager, "foo.TopLevel.Inner.Inner.Inner");
|
||||
}
|
||||
|
||||
public void testInnerClassesWithDollars() throws Exception {
|
||||
CoreJavaFileManager manager = configureManager("package foo;\n\n" +
|
||||
"public class TopLevel {\n" +
|
||||
|
||||
"public class I$nner {" +
|
||||
" public class I$nner{}" +
|
||||
" public class $Inner{}" +
|
||||
" public class In$ne$r${}" +
|
||||
" public class Inner$${}" +
|
||||
" public class $$$$${}" +
|
||||
"}\n" +
|
||||
"public class Inner$ {" +
|
||||
" public class I$nner{}" +
|
||||
" public class $Inner{}" +
|
||||
" public class In$ne$r${}" +
|
||||
" public class Inner$${}" +
|
||||
" public class $$$$${}" +
|
||||
"}\n" +
|
||||
"public class In$ner$$ {" +
|
||||
" public class I$nner{}" +
|
||||
" public class $Inner{}" +
|
||||
" public class In$ne$r${}" +
|
||||
" public class Inner$${}" +
|
||||
" public class $$$$${}" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"}", "TopLevel");
|
||||
|
||||
assertCanFind(manager, "foo.TopLevel");
|
||||
|
||||
assertCanFind(manager, "foo.TopLevel.I$nner");
|
||||
assertCanFind(manager, "foo.TopLevel.I$nner.I$nner");
|
||||
assertCanFind(manager, "foo.TopLevel.I$nner.$Inner");
|
||||
assertCanFind(manager, "foo.TopLevel.I$nner.In$ne$r$");
|
||||
assertCanFind(manager, "foo.TopLevel.I$nner.Inner$$");
|
||||
assertCanFind(manager, "foo.TopLevel.I$nner.$$$$$");
|
||||
|
||||
assertCannotFind(manager, "foo.TopLevel.I.nner.$$$$$");
|
||||
|
||||
assertCanFind(manager, "foo.TopLevel.Inner$");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner$.I$nner");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner$.$Inner");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner$.In$ne$r$");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner$.Inner$$");
|
||||
assertCanFind(manager, "foo.TopLevel.Inner$.$$$$$");
|
||||
|
||||
assertCannotFind(manager, "foo.TopLevel.Inner..$$$$$");
|
||||
|
||||
assertCanFind(manager, "foo.TopLevel.In$ner$$");
|
||||
assertCanFind(manager, "foo.TopLevel.In$ner$$.I$nner");
|
||||
assertCanFind(manager, "foo.TopLevel.In$ner$$.$Inner");
|
||||
assertCanFind(manager, "foo.TopLevel.In$ner$$.In$ne$r$");
|
||||
assertCanFind(manager, "foo.TopLevel.In$ner$$.Inner$$");
|
||||
assertCanFind(manager, "foo.TopLevel.In$ner$$.$$$$$");
|
||||
|
||||
assertCannotFind(manager, "foo.TopLevel.In.ner$$.$$$$$");
|
||||
}
|
||||
|
||||
public void testTopLevelClassesWithDollars() throws Exception {
|
||||
CoreJavaFileManager inTheMiddle = configureManager("package foo;\n\n public class Top$Level {}", "Top$Level");
|
||||
assertCanFind(inTheMiddle, "foo.Top$Level");
|
||||
|
||||
CoreJavaFileManager doubleAtTheEnd = configureManager("package foo;\n\n public class TopLevel$$ {}", "TopLevel$$");
|
||||
assertCanFind(doubleAtTheEnd, "foo.TopLevel$$");
|
||||
|
||||
CoreJavaFileManager multiple = configureManager("package foo;\n\n public class Top$Lev$el$ {}", "Top$Lev$el$");
|
||||
assertCanFind(multiple, "foo.Top$Lev$el$");
|
||||
assertCannotFind(multiple, "foo.Top.Lev$el$");
|
||||
|
||||
CoreJavaFileManager twoBucks = configureManager("package foo;\n\n public class $$ {}", "$$");
|
||||
assertCanFind(twoBucks, "foo.$$");
|
||||
}
|
||||
|
||||
public void testTopLevelClassWithDollarsAndInners() throws Exception {
|
||||
CoreJavaFileManager manager = configureManager("package foo;\n\n" +
|
||||
"public class Top$Level$$ {\n" +
|
||||
|
||||
"public class I$nner {" +
|
||||
" public class I$nner{}" +
|
||||
" public class In$ne$r${}" +
|
||||
" public class Inner$$$$${}" +
|
||||
" public class $Inner{}" +
|
||||
" public class ${}" +
|
||||
" public class $$$$${}" +
|
||||
"}\n" +
|
||||
"public class Inner {" +
|
||||
" public class Inner{}" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"}", "Top$Level$$");
|
||||
|
||||
assertCanFind(manager, "foo.Top$Level$$");
|
||||
|
||||
assertCanFind(manager, "foo.Top$Level$$.Inner");
|
||||
assertCanFind(manager, "foo.Top$Level$$.Inner.Inner");
|
||||
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner");
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner.I$nner");
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner.In$ne$r$");
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner.Inner$$$$$");
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner.$Inner");
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner.$");
|
||||
assertCanFind(manager, "foo.Top$Level$$.I$nner.$$$$$");
|
||||
|
||||
assertCannotFind(manager, "foo.Top.Level$$.I$nner.$$$$$");
|
||||
}
|
||||
|
||||
public void testDoNotThrowOnMalformedInput() throws Exception {
|
||||
CoreJavaFileManager fileWithEmptyName = configureManager("package foo;\n\n public class Top$Level {}", "");
|
||||
assertCannotFind(fileWithEmptyName, "foo.");
|
||||
assertCannotFind(fileWithEmptyName, ".");
|
||||
assertCannotFind(fileWithEmptyName, "..");
|
||||
assertCannotFind(fileWithEmptyName, "");
|
||||
assertCannotFind(fileWithEmptyName, ".foo");
|
||||
}
|
||||
|
||||
public void testSeveralClassesInOneFile() throws Exception {
|
||||
CoreJavaFileManager manager = configureManager("package foo;\n\n" +
|
||||
"public class One {}\n" +
|
||||
"class Two {}\n" +
|
||||
"class Three {}", "One");
|
||||
|
||||
assertCanFind(manager, "foo.One");
|
||||
|
||||
//NOTE: this is unsupported
|
||||
assertCannotFind(manager, "foo.Two");
|
||||
assertCannotFind(manager, "foo.Three");
|
||||
}
|
||||
|
||||
public void testScopeCheck() throws Exception {
|
||||
CoreJavaFileManager manager = configureManager("package foo;\n\n" + "public class Test {}\n", "Test");
|
||||
|
||||
assertNotNull("Should find class in all scope", manager.findClass("foo.Test", GlobalSearchScope.allScope(getProject())));
|
||||
assertNull("Should not find class in empty scope", manager.findClass("foo.Test", GlobalSearchScope.EMPTY_SCOPE));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private CoreJavaFileManager configureManager(@Language("JAVA") @NotNull String text, @NotNull String className) throws Exception {
|
||||
VirtualFile root = PsiTestUtil.createTestProjectStructure(myProject, myModule, myFilesToDelete);
|
||||
VirtualFile pkg = root.createChildDirectory(this, "foo");
|
||||
PsiDirectory dir = myPsiManager.findDirectory(pkg);
|
||||
assertNotNull(dir);
|
||||
dir.add(PsiFileFactory.getInstance(getProject()).createFileFromText(clazzName + ".java", JavaFileType.INSTANCE, clazzData));
|
||||
return root;
|
||||
}
|
||||
|
||||
public void testNotNullInnerClass() throws Exception {
|
||||
String text = "package foo;\n\n" +
|
||||
"public class Nested {\n" +
|
||||
"public class InnerGeneral {}\n" +
|
||||
"public class Inner$ {" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"public Inner$ inner() {\n" +
|
||||
" return new Inner$();\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"}";
|
||||
|
||||
VirtualFile root = prepareClasses("Nested", text);
|
||||
GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
|
||||
dir.add(PsiFileFactory.getInstance(getProject()).createFileFromText(className + ".java", JavaFileType.INSTANCE, text));
|
||||
CoreJavaFileManager manager = new CoreJavaFileManager(myPsiManager);
|
||||
manager.addToClasspath(root);
|
||||
|
||||
PsiClass clazz = manager.findClass("foo.Nested", scope);
|
||||
assertNotNull(clazz);
|
||||
|
||||
PsiClass clazzInnerGeneral = manager.findClass("foo.Nested.InnerGeneral", scope);
|
||||
assertNotNull(clazzInnerGeneral);
|
||||
|
||||
PsiClass clazzInner$ = manager.findClass("foo.Nested.Inner$", scope);
|
||||
assertNotNull(clazzInner$);
|
||||
|
||||
PsiClass clazzInner$Wrong1 = manager.findClass("foo.Nested.Inner$X", scope);
|
||||
assertNull(clazzInner$Wrong1);
|
||||
|
||||
PsiClass clazzInner$Wrong2 = manager.findClass("foo.Nested.Inner$$X", scope);
|
||||
assertNull(clazzInner$Wrong2);
|
||||
|
||||
PsiClass clazzInner$Wrong3 = manager.findClass("foo.Nested.Inner$$", scope);
|
||||
assertNull(clazzInner$Wrong3);
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
||||
public void testNotNullInnerClass2() throws Exception {
|
||||
String text = "package foo;\n\n" +
|
||||
"public class Nested {\n" +
|
||||
|
||||
"public class Inner {" +
|
||||
" public class XInner{}" +
|
||||
" public class XInner${}" +
|
||||
"}\n" +
|
||||
"public class Inner$ {" +
|
||||
" public class XInner{}" +
|
||||
" public class XInner${}" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"}";
|
||||
|
||||
VirtualFile root = prepareClasses("Nested", text);
|
||||
GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
|
||||
CoreJavaFileManager manager = new CoreJavaFileManager(myPsiManager);
|
||||
manager.addToClasspath(root);
|
||||
|
||||
PsiClass clazzInner = manager.findClass("foo.Nested.Inner", scope);
|
||||
assertNotNull(clazzInner);
|
||||
|
||||
PsiClass clazzXInner = manager.findClass("foo.Nested.Inner.XInner", scope);
|
||||
assertNotNull(clazzXInner);
|
||||
|
||||
PsiClass clazzXInner$ = manager.findClass("foo.Nested.Inner.XInner$", scope);
|
||||
assertNotNull(clazzXInner$);
|
||||
|
||||
PsiClass clazz$XInner = manager.findClass("foo.Nested.Inner$.XInner", scope);
|
||||
assertNotNull(clazz$XInner);
|
||||
|
||||
PsiClass clazz$XInner$ = manager.findClass("foo.Nested.Inner$.XInner$", scope);
|
||||
assertNotNull(clazz$XInner$);
|
||||
private void assertCanFind(@NotNull CoreJavaFileManager manager, @NotNull String qName) {
|
||||
PsiClass foundClass = manager.findClass(qName, GlobalSearchScope.allScope(getProject()));
|
||||
assertNotNull("Could not find:" + qName, foundClass);
|
||||
assertEquals("Found " + foundClass.getQualifiedName() + " instead of " + qName, qName, foundClass.getQualifiedName());
|
||||
}
|
||||
|
||||
|
||||
public void testNotNullInnerClass3() throws Exception {
|
||||
String text = "package foo;\n\n" +
|
||||
"public class NestedX {\n" +
|
||||
|
||||
"public class XX {" +
|
||||
" public class XXX{" +
|
||||
" public class XXXX{ }" +
|
||||
" public class XXXX${ }" +
|
||||
" }" +
|
||||
" public class XXX${" +
|
||||
" public class XXXX{ }" +
|
||||
" public class XXXX${ }" +
|
||||
" }" +
|
||||
"}\n" +
|
||||
"public class XX$ {" +
|
||||
" public class XXX{" +
|
||||
" public class XXXX{ }" +
|
||||
" public class XXXX${ }" +
|
||||
" }" +
|
||||
" public class XXX${" +
|
||||
" public class XXXX{ }" +
|
||||
" public class XXXX${ }" +
|
||||
" }" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"}";
|
||||
|
||||
VirtualFile root = prepareClasses("NestedX", text);
|
||||
GlobalSearchScope scope = GlobalSearchScope.allScope(getProject());
|
||||
CoreJavaFileManager manager = new CoreJavaFileManager(myPsiManager);
|
||||
manager.addToClasspath(root);
|
||||
|
||||
Queue<String> queue = new LinkedList<String>();
|
||||
queue.add("foo.NestedX");
|
||||
|
||||
while(!queue.isEmpty()) {
|
||||
String head = queue.remove();
|
||||
PsiClass clazzInner = manager.findClass(head, scope);
|
||||
assertNotNull(head, clazzInner);
|
||||
String lastSegment = head.substring(head.lastIndexOf('.'));
|
||||
String xs = lastSegment.substring(lastSegment.indexOf("X")).replace("$", "");
|
||||
if (xs.length() < 4) {
|
||||
queue.add(head + "." + xs + "X");
|
||||
queue.add(head + "." + xs + "X$");
|
||||
}
|
||||
}
|
||||
private void assertCannotFind(@NotNull CoreJavaFileManager manager, @NotNull String qName) {
|
||||
PsiClass foundClass = manager.findClass(qName, GlobalSearchScope.allScope(getProject()));
|
||||
assertNull("Found, but shouldn't have:" + qName, foundClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -22,7 +22,7 @@
|
||||
</constraints>
|
||||
<properties>
|
||||
<selected value="true"/>
|
||||
<text value="Unlock files"/>
|
||||
<text value="I want to edit these files anyway"/>
|
||||
</properties>
|
||||
</component>
|
||||
<component id="592c9" class="javax.swing.JRadioButton" binding="myUnlockAllButton" default-binding="true">
|
||||
@@ -30,7 +30,7 @@
|
||||
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text value="Unlock all non-project files in current session"/>
|
||||
<text value="I want to edit any non-project file in the current session"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
|
||||
+5
-1
@@ -38,9 +38,13 @@ public class NonProjectFileWritingAccessDialog extends DialogWrapper {
|
||||
myFileList.setCellRenderer(new FileListRenderer());
|
||||
myFileList.setModel(new CollectionListModel<VirtualFile>(nonProjectFiles));
|
||||
|
||||
getOKAction().putValue(DEFAULT_ACTION, null);
|
||||
getCancelAction().putValue(DEFAULT_ACTION, true);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
@@ -54,6 +58,6 @@ public class NonProjectFileWritingAccessDialog extends DialogWrapper {
|
||||
}
|
||||
|
||||
protected String getHelpId() {
|
||||
return "readOnlyHandler.nonProjectFilesDialog";
|
||||
return "Non-Project_Files_Access_Dialog";
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -2135,7 +2135,8 @@ utility.class.code.can.be.enum.quickfix=Convert to 'enum'
|
||||
non.public.clone.display.name='clone()' method not 'public'
|
||||
non.public.clone.problem.descriptor=<code>#ref()</code> method not 'public' #loc
|
||||
only.warn.on.public.clone.methods=Only warn on 'public' clone methods
|
||||
only.warn.on.protected.clone.methods=Only warn on 'protected' clone methods
|
||||
clone.returns.class.type.display.name='clone()' should have return type equal to the class it contains
|
||||
clone.returns.class.type.problem.descriptor=''clone()'' should have return type ''{0}'' #loc
|
||||
clone.returns.class.type.quickfix=Change return type to '{0}'
|
||||
clone.returns.class.type.quickfix=Change return type to ''{0}''
|
||||
clone.returns.class.type.family.quickfix=Change return type to class type
|
||||
|
||||
+3
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2014 Bas Leijdekkers
|
||||
* Copyright 2006-2015 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package com.siyeh.ig.abstraction;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
|
||||
import com.intellij.codeInspection.ProblemDescriptor;
|
||||
import com.intellij.codeInspection.ui.MultipleCheckboxOptionsPanel;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
@@ -294,7 +295,7 @@ public class TypeMayBeWeakenedInspection extends BaseInspection {
|
||||
@Override
|
||||
public void visitMethod(PsiMethod method) {
|
||||
super.visitMethod(method);
|
||||
if (isOnTheFly() && !method.hasModifierProperty(PsiModifier.PRIVATE)) {
|
||||
if (isOnTheFly() && !method.hasModifierProperty(PsiModifier.PRIVATE) && !ApplicationManager.getApplication().isUnitTestMode()) {
|
||||
// checking methods with greater visibility is too expensive.
|
||||
// for error checking in the editor
|
||||
return;
|
||||
|
||||
+9
-9
@@ -39,7 +39,7 @@ import javax.swing.*;
|
||||
|
||||
public class CloneDeclaresCloneNotSupportedInspection extends BaseInspection {
|
||||
|
||||
private boolean onlyWarnOnPublicClone = true;
|
||||
private boolean onlyWarnOnProtectedClone = true;
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@@ -67,16 +67,16 @@ public class CloneDeclaresCloneNotSupportedInspection extends BaseInspection {
|
||||
@Nullable
|
||||
@Override
|
||||
public JComponent createOptionsPanel() {
|
||||
return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("only.warn.on.public.clone.methods"),
|
||||
this, "onlyWarnOnPublicClone");
|
||||
return new SingleCheckboxOptionsPanel(InspectionGadgetsBundle.message("only.warn.on.protected.clone.methods"),
|
||||
this, "onlyWarnOnProtectedClone");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void readSettings(@NotNull Element node) throws InvalidDataException {
|
||||
super.readSettings(node);
|
||||
for (Element option : node.getChildren("option")) {
|
||||
if ("onlyWarnOnPublicClone".equals(option.getAttributeValue("name"))) {
|
||||
onlyWarnOnPublicClone = Boolean.parseBoolean(option.getAttributeValue("value"));
|
||||
if ("onlyWarnOnProtectedClone".equals(option.getAttributeValue("name"))) {
|
||||
onlyWarnOnProtectedClone = Boolean.parseBoolean(option.getAttributeValue("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,9 +84,9 @@ public class CloneDeclaresCloneNotSupportedInspection extends BaseInspection {
|
||||
@Override
|
||||
public void writeSettings(@NotNull Element node) throws WriteExternalException {
|
||||
super.writeSettings(node);
|
||||
if (!onlyWarnOnPublicClone) {
|
||||
node.addContent(new Element("option").setAttribute("name", "onlyWarnOnPublicClone")
|
||||
.setAttribute("value", String.valueOf(onlyWarnOnPublicClone)));
|
||||
if (!onlyWarnOnProtectedClone) {
|
||||
node.addContent(new Element("option").setAttribute("name", "onlyWarnOnProtectedClone")
|
||||
.setAttribute("value", String.valueOf(onlyWarnOnProtectedClone)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ public class CloneDeclaresCloneNotSupportedInspection extends BaseInspection {
|
||||
if (method.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return;
|
||||
}
|
||||
if (onlyWarnOnPublicClone && !method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
if (onlyWarnOnProtectedClone && method.hasModifierProperty(PsiModifier.PUBLIC)) {
|
||||
return;
|
||||
}
|
||||
final PsiClass containingClass = method.getContainingClass();
|
||||
|
||||
+4
-11
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2013 Dave Griffith, Bas Leijdekkers
|
||||
* Copyright 2006-2015 Dave Griffith, Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,7 +52,7 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection {
|
||||
}
|
||||
final RefClass refClass = (RefClass)refEntity;
|
||||
final PsiClass aClass = refClass.getElement();
|
||||
if (aClass == null || aClass.getContainingClass() != null) {
|
||||
if (aClass == null || aClass.getContainingClass() != null || aClass instanceof PsiAnonymousClass) {
|
||||
return null;
|
||||
}
|
||||
final Set<RefClass> dependencies = DependencyUtils.calculateTransitiveDependenciesForClass(refClass);
|
||||
@@ -79,15 +79,8 @@ public class CyclicClassDependencyInspection extends BaseGlobalInspection {
|
||||
errorString = InspectionGadgetsBundle.message("cyclic.class.dependency.problem.descriptor",
|
||||
refEntity.getName(), Integer.valueOf(numMutualDependents));
|
||||
}
|
||||
final PsiElement anchor;
|
||||
if (aClass instanceof PsiAnonymousClass) {
|
||||
final PsiAnonymousClass anonymousClass = (PsiAnonymousClass)aClass;
|
||||
anchor = anonymousClass.getBaseClassReference();
|
||||
}
|
||||
else {
|
||||
anchor = aClass.getNameIdentifier();
|
||||
if (anchor == null) return null;
|
||||
}
|
||||
final PsiElement anchor = aClass.getNameIdentifier();
|
||||
if (anchor == null) return null;
|
||||
return new CommonProblemDescriptor[]{
|
||||
inspectionManager.createProblemDescriptor(anchor, errorString, (LocalQuickFix)null,
|
||||
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, false)
|
||||
|
||||
+10
-4
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2014 Bas Leijdekkers
|
||||
* Copyright 2008-2015 Bas Leijdekkers
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -155,11 +155,17 @@ public class WeakestTypeFinder {
|
||||
checkClass(javaLangIterableClass, weakestTypeClasses);
|
||||
}
|
||||
else if (referenceParent instanceof PsiReturnStatement) {
|
||||
final PsiMethod containingMethod = PsiTreeUtil.getParentOfType(referenceParent, PsiMethod.class);
|
||||
if (containingMethod == null) {
|
||||
final PsiElement owner = PsiTreeUtil.getParentOfType(referenceParent, PsiMethod.class, PsiLambdaExpression.class);
|
||||
final PsiType type;
|
||||
if (owner instanceof PsiMethod) {
|
||||
type = ((PsiMethod)owner).getReturnType();
|
||||
}
|
||||
else if (owner instanceof PsiLambdaExpression) {
|
||||
type = LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)owner);
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
final PsiType type = containingMethod.getReturnType();
|
||||
if (!checkType(type, weakestTypeClasses)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
+2
-2
@@ -8,9 +8,9 @@ prohibit cloning will not be able to do so in the standard way. This inspection
|
||||
or <b>clone()</b> methods on <b>final</b> classes.
|
||||
<!-- tooltip end -->
|
||||
<p>
|
||||
Use the checkbox below to indicate if this inspection should only warn on <b>public</b> methods.
|
||||
Use the checkbox below to indicate if this inspection should only warn on <b>protected</b> methods.
|
||||
In <i>Effective Java, Second Edition</i> (but not in the first edition) it is recommended to omit the <b>CloneNotSupportedException</b>
|
||||
declaration, because methods that don't throw checked exceptions are easier to use.
|
||||
declaration on <b>public</b> methods, because methods that don't throw checked exceptions are easier to use.
|
||||
<p>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.siyeh.igtest.abstraction.weaken_type;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface Lambda {
|
||||
|
||||
int count();
|
||||
|
||||
static Lambda newWeaken(int value) {
|
||||
return new Lambda() {
|
||||
@Override
|
||||
public int count() {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
static Supplier<Lambda> newSupplier() {
|
||||
return () -> {
|
||||
return Lambda.newWeaken(0);
|
||||
};
|
||||
}
|
||||
}
|
||||
+11
-1
@@ -8,7 +8,7 @@ public class CloneDeclaresCloneNonSupportedException implements Cloneable
|
||||
|
||||
}
|
||||
|
||||
public Object clone()
|
||||
protected Object <warning descr="'clone()' does not declare 'CloneNotSupportedException'">clone</warning>()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -34,3 +34,13 @@ class Child extends CloneDeclaresCloneNonSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
}
|
||||
class NoWarnOnPublic implements Cloneable {
|
||||
|
||||
public Object clone() {
|
||||
try {
|
||||
return super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-9
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>CloneDeclaresCloneNonSupportedException.java</file>
|
||||
<line>11</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">'clone()' does not declare 'CloneNotSupportedException'</problem_class>
|
||||
<description><code>clone()</code> does not declare 'CloneNotSupportedException'</description>
|
||||
</problem>
|
||||
</problems>
|
||||
-7
@@ -1,12 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<problems>
|
||||
<problem>
|
||||
<file>Cyclic.java</file>
|
||||
<line>9</line>
|
||||
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">Cyclic class dependency</problem_class>
|
||||
<description>Class 'anonymous (java.lang.Object)' is cyclically dependent on 3 other classes</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>Cyclic.java</file>
|
||||
<line>17</line>
|
||||
|
||||
+15
@@ -27,3 +27,18 @@ interface FiveOClock {
|
||||
|
||||
}
|
||||
interface Coffee extends FiveOClock {}
|
||||
enum MyEnum {
|
||||
ONE {
|
||||
public int value() {
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
|
||||
TWO {
|
||||
public int value() {
|
||||
return ONE.value();
|
||||
}
|
||||
};
|
||||
|
||||
abstract int value();
|
||||
}
|
||||
|
||||
+6
@@ -9,6 +9,7 @@ public class TypeMayBeWeakenedInspectionTest extends LightInspectionTestCase {
|
||||
public void testTypeMayBeWeakened() { doTest(); }
|
||||
public void testNumberAdderDemo() { doTest(); }
|
||||
public void testAutoClosableTest() { doTest(); }
|
||||
public void testLambda() { doTest(); }
|
||||
|
||||
@Override
|
||||
protected String[] getEnvironmentClasses() {
|
||||
@@ -33,6 +34,11 @@ public class TypeMayBeWeakenedInspectionTest extends LightInspectionTestCase {
|
||||
"@FunctionalInterface " +
|
||||
"public interface Function<T, R> {" +
|
||||
" R apply(T t);" +
|
||||
"}",
|
||||
"package java.util.function;\n" +
|
||||
"@FunctionalInterface\n" +
|
||||
"public interface Supplier<T> {\n" +
|
||||
" T get();\n" +
|
||||
"}"
|
||||
};
|
||||
}
|
||||
|
||||
+12
-4
@@ -1,10 +1,18 @@
|
||||
package com.siyeh.ig.cloneable;
|
||||
|
||||
import com.siyeh.ig.IGInspectionTestCase;
|
||||
import com.intellij.codeInspection.InspectionProfileEntry;
|
||||
import com.siyeh.ig.LightInspectionTestCase;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CloneDeclaresCloneNotSupportedInspectionTest extends IGInspectionTestCase {
|
||||
public class CloneDeclaresCloneNotSupportedInspectionTest extends LightInspectionTestCase {
|
||||
|
||||
public void test() throws Exception {
|
||||
doTest("com/siyeh/igtest/cloneable/clone_declares_clone_not_supported", new CloneDeclaresCloneNotSupportedInspection());
|
||||
public void testCloneDeclaresCloneNonSupportedException() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected InspectionProfileEntry getInspection() {
|
||||
return new CloneDeclaresCloneNotSupportedInspection();
|
||||
}
|
||||
}
|
||||
+2
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -416,6 +416,7 @@ public class DeadCodeHelper {
|
||||
|
||||
if (sameRanges) {
|
||||
seq.addSequence(next.getSeq());
|
||||
block.getInstrOldOffsets().addAll(next.getInstrOldOffsets());
|
||||
next.getSeq().clear();
|
||||
|
||||
removeEmptyBlock(graph, next, true);
|
||||
|
||||
@@ -16,7 +16,7 @@ public class TestClassLoop {
|
||||
return;
|
||||
}
|
||||
} finally {
|
||||
System.out.println("1");
|
||||
System.out.println("1");// 38
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ public class TestClassLoop {
|
||||
System.out.println("1");// 49
|
||||
break;
|
||||
} finally {
|
||||
if(var0) {
|
||||
if(var0) {// 52
|
||||
System.out.println("3");// 53
|
||||
continue;
|
||||
}
|
||||
@@ -54,6 +54,9 @@ class 'pkg/TestClassLoop' {
|
||||
4 10
|
||||
d 10
|
||||
f 14
|
||||
26 18
|
||||
27 18
|
||||
2a 18
|
||||
}
|
||||
|
||||
method 'testFinallyContinue ()V' {
|
||||
@@ -64,6 +67,7 @@ class 'pkg/TestClassLoop' {
|
||||
e 29
|
||||
11 29
|
||||
13 29
|
||||
26 32
|
||||
2a 33
|
||||
2d 33
|
||||
2f 33
|
||||
@@ -74,6 +78,8 @@ Lines mapping:
|
||||
23 <-> 6
|
||||
29 <-> 11
|
||||
33 <-> 15
|
||||
38 <-> 19
|
||||
45 <-> 25
|
||||
49 <-> 30
|
||||
52 <-> 33
|
||||
53 <-> 34
|
||||
|
||||
@@ -22,9 +22,9 @@ public class TestClassSimpleBytecodeMapping {
|
||||
try {
|
||||
Integer.parseInt(var1);// 34
|
||||
} catch (Exception var6) {
|
||||
System.out.println(var6);
|
||||
System.out.println(var6);// 36
|
||||
} finally {
|
||||
System.out.println("Finally");
|
||||
System.out.println("Finally");// 38
|
||||
}
|
||||
|
||||
}
|
||||
@@ -80,6 +80,11 @@ class 'pkg/TestClassSimpleBytecodeMapping' {
|
||||
|
||||
method 'test2 (Ljava/lang/String;)V' {
|
||||
1 22
|
||||
11 24
|
||||
15 24
|
||||
23 26
|
||||
24 26
|
||||
27 26
|
||||
}
|
||||
|
||||
method 'run (Ljava/lang/Runnable;)V' {
|
||||
@@ -114,6 +119,8 @@ Lines mapping:
|
||||
27 <-> 16
|
||||
28 <-> 17
|
||||
34 <-> 23
|
||||
36 <-> 25
|
||||
38 <-> 27
|
||||
44 <-> 44
|
||||
49 <-> 33
|
||||
54 <-> 38
|
||||
|
||||
@@ -9,7 +9,7 @@ public class TestClassVar {
|
||||
try {
|
||||
System.out.println();// 29
|
||||
} finally {
|
||||
if(this.field_boolean) {
|
||||
if(this.field_boolean) {// 32
|
||||
System.out.println();// 33
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ class 'pkg/TestClassVar' {
|
||||
3 7
|
||||
8 9
|
||||
b 9
|
||||
1f 11
|
||||
20 11
|
||||
26 12
|
||||
29 12
|
||||
}
|
||||
@@ -73,6 +75,7 @@ class 'pkg/TestClassVar' {
|
||||
Lines mapping:
|
||||
26 <-> 8
|
||||
29 <-> 10
|
||||
32 <-> 12
|
||||
33 <-> 13
|
||||
40 <-> 22
|
||||
45 <-> 26
|
||||
|
||||
@@ -16,6 +16,7 @@ class 'pkg/TestSynchronizedMapping' {
|
||||
method 'test (I)I' {
|
||||
3 4
|
||||
5 5
|
||||
a 5
|
||||
}
|
||||
|
||||
method 'test2 (Ljava/lang/String;)V' {
|
||||
|
||||
@@ -11,7 +11,7 @@ public class TestTryCatchFinally {
|
||||
;
|
||||
}
|
||||
} finally {
|
||||
System.out.println("finally");
|
||||
System.out.println("finally");// 34
|
||||
}
|
||||
|
||||
}
|
||||
@@ -31,9 +31,9 @@ public class TestTryCatchFinally {
|
||||
int var2 = Integer.parseInt(var1);// 51
|
||||
return var2;
|
||||
} catch (Exception var6) {
|
||||
System.out.println("Error" + var6);
|
||||
System.out.println("Error" + var6);// 53
|
||||
} finally {
|
||||
System.out.println("Finally");
|
||||
System.out.println("Finally");// 55
|
||||
}
|
||||
|
||||
return -1;
|
||||
@@ -48,6 +48,9 @@ class 'pkg/TestTryCatchFinally' {
|
||||
14 8
|
||||
17 8
|
||||
19 8
|
||||
2b 13
|
||||
2d 13
|
||||
30 13
|
||||
}
|
||||
|
||||
method 'foo (I)I' {
|
||||
@@ -63,15 +66,25 @@ class 'pkg/TestTryCatchFinally' {
|
||||
method 'test (Ljava/lang/String;)I' {
|
||||
1 30
|
||||
4 30
|
||||
10 33
|
||||
1a 33
|
||||
23 33
|
||||
26 33
|
||||
34 35
|
||||
35 35
|
||||
38 35
|
||||
}
|
||||
}
|
||||
|
||||
Lines mapping:
|
||||
24 <-> 6
|
||||
27 <-> 9
|
||||
34 <-> 14
|
||||
39 <-> 20
|
||||
40 <-> 21
|
||||
41 <-> 22
|
||||
42 <-> 23
|
||||
45 <-> 25
|
||||
51 <-> 31
|
||||
53 <-> 34
|
||||
55 <-> 36
|
||||
|
||||
Reference in New Issue
Block a user