import layout for Groovy IDEA-87823

This commit is contained in:
Maxim.Medvedev
2012-07-12 20:15:34 +04:00
parent e3299b2a28
commit 8e0ea8b99f
23 changed files with 699 additions and 561 deletions
@@ -23,6 +23,7 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.containers.ContainerUtilRt;
import com.intellij.util.containers.HashSet;
import gnu.trove.TObjectIntHashMap;
import gnu.trove.TObjectIntProcedure;
@@ -30,7 +31,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.*;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
@@ -38,8 +38,6 @@ import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import java.util.*;
import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil.isImportToJavaOrJavax;
/**
* @author ven
*/
@@ -52,7 +50,7 @@ public class GroovyImportOptimizer implements ImportOptimizer {
public static Set<GrImportStatement> findUsedImports(GroovyFile file) {
Set<GrImportStatement> usedImports = new HashSet<GrImportStatement>();
processFile(file, null, null, usedImports, null, null);
processFile(file, null, null, usedImports, null, null, null, null);
return usedImports;
}
@@ -65,7 +63,9 @@ public class GroovyImportOptimizer implements ImportOptimizer {
@Nullable final Set<String> staticallyImportedMembers,
@Nullable final Set<GrImportStatement> usedImports,
@Nullable final Set<String> implicitlyImported,
@Nullable final Set<String> innerClasses) {
@Nullable final Set<String> innerClasses,
@Nullable final Map<String, String> aliased,
@Nullable final Map<String, String> annotations) {
if (!(file instanceof GroovyFile)) return;
((GroovyFile)file).accept(new GroovyRecursiveElementVisitor() {
@@ -91,7 +91,8 @@ public class GroovyImportOptimizer implements ImportOptimizer {
if (usedImports != null) {
usedImports.add(importStatement);
}
if (!importStatement.isAliasedImport()) {
if (!importStatement.isAliasedImport() && !isAnnotatedImport(importStatement)) {
String importedName = null;
if (importStatement.isOnDemand()) {
@@ -123,6 +124,22 @@ public class GroovyImportOptimizer implements ImportOptimizer {
if (importedName == null) return;
final String importRef = getImportReferenceText(importStatement);
if (annotations != null) {
if (isAnnotatedImport(importStatement)) {
annotations.put(importRef, importStatement.getAnnotationList().getText());
}
}
if (importStatement.isAliasedImport()) {
if (aliased != null) {
aliased.put(importRef, importedName);
}
return;
}
if (importStatement.isStatic()) {
if (staticallyImportedMembers != null) {
staticallyImportedMembers.add(importedName);
@@ -183,12 +200,15 @@ public class GroovyImportOptimizer implements ImportOptimizer {
if (document != null) {
documentManager.commitDocument(document);
}
final Set<String> importedClasses = new LinkedHashSet<String>();
final Set<String> simplyImportedClasses = new LinkedHashSet<String>();
final Set<String> staticallyImportedMembers = new LinkedHashSet<String>();
final Set<GrImportStatement> usedImports = new HashSet<GrImportStatement>();
final Set<String> implicitlyImported = new LinkedHashSet<String>();
final HashSet<String> innerClasses = new HashSet<String>();
processFile(myFile, importedClasses, staticallyImportedMembers, usedImports, implicitlyImported, innerClasses);
final Set<String> implicitlyImportedClasses = new LinkedHashSet<String>();
final Set<String> innerClasses = new HashSet<String>();
Map<String, String> aliasImported = ContainerUtilRt.newHashMap();
Map<String, String> annotatedImports = ContainerUtilRt.newHashMap();
processFile(myFile, simplyImportedClasses, staticallyImportedMembers, usedImports, implicitlyImportedClasses, innerClasses, aliasImported, annotatedImports);
final List<GrImportStatement> oldImports = PsiUtil.getValidImportStatements(file);
if (myRemoveUnusedOnly) {
for (GrImportStatement oldImport : oldImports) {
@@ -199,48 +219,23 @@ public class GroovyImportOptimizer implements ImportOptimizer {
return;
}
Map<String, String> annotations = new HashMap<String, String>();
// Getting aliased imports
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(file.getProject());
ArrayList<GrImportStatement> aliased = new ArrayList<GrImportStatement>();
for (GrImportStatement oldImport : oldImports) {
if (oldImport.isAliasedImport() && usedImports.contains(oldImport)) {
aliased.add(factory.createImportStatementFromText(oldImport.getText()));
}
else {
String importReference = getImportReferenceText(oldImport);
GrModifierList annotationList = oldImport.getAnnotationList();
if (importReference != null && annotationList != null) {
annotations.put(importReference, annotationList.getText());
}
}
}
// Add new import statements
GrImportStatement[] newImports = prepare(importedClasses, staticallyImportedMembers, implicitlyImported, innerClasses);
if (oldImports.isEmpty() && newImports.length == 0 && aliased.isEmpty()) {
GrImportStatement[] newImports = prepare(usedImports, simplyImportedClasses, staticallyImportedMembers, implicitlyImportedClasses, innerClasses, aliasImported, annotatedImports);
if (oldImports.isEmpty() && newImports.length == 0 && aliasImported.isEmpty()) {
return;
}
GroovyFile tempFile = (GroovyFile)PsiFileFactory.getInstance(file.getProject()).createFileFromText("a.groovy", "");
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(file.getProject());
GroovyFile tempFile = factory.createGroovyFile("", false, null);
for (GrImportStatement aliasedImport : aliased) {
tempFile.addImport(aliasedImport);
}
for (GrImportStatement newImport : newImports) {
String imported = getImportReferenceText(newImport);
String annos = annotations.get(imported);
if (imported != null && StringUtil.isNotEmpty(annos)) {
newImport = factory.createImportStatementFromText(annos + " " + newImport.getText());
}
tempFile.addImport(newImport);
}
String oldText = oldImports.isEmpty() ? "" :
myFile.getText().substring(oldImports.get(0).getTextRange().getStartOffset(),
oldImports.get(oldImports.size() - 1).getTextRange().getEndOffset());
final int startOffset = oldImports.get(0).getTextRange().getStartOffset();
final int endOffset = oldImports.get(oldImports.size() - 1).getTextRange().getEndOffset();
String oldText = oldImports.isEmpty() ? "" : myFile.getText().substring(startOffset, endOffset);
if (tempFile.getText().trim().equals(oldText)) {
return;
}
@@ -249,26 +244,18 @@ public class GroovyImportOptimizer implements ImportOptimizer {
file.addImport(statement);
}
file.removeImport(file.addImport(factory.createImportStatementFromText("import xxxx"))); //to remove trailing whitespaces
for (GrImportStatement importStatement : oldImports) {
file.removeImport(importStatement);
}
}
@Nullable
private String getImportReferenceText(GrImportStatement statement) {
GrCodeReferenceElement importReference = statement.getImportReference();
if (importReference != null) {
return statement.getText().substring(importReference.getStartOffsetInParent());
}
return null;
}
private GrImportStatement[] prepare(Set<String> importedClasses,
private GrImportStatement[] prepare(final Set<GrImportStatement> usedImports,
Set<String> importedClasses,
Set<String> staticallyImportedMembers,
Set<String> implicitlyImported,
Set<String> innerClasses) {
Set<String> innerClasses,
Map<String, String> aliased,
final Map<String, String> annotations) {
final Project project = myFile.getProject();
final CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(project);
final GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
@@ -277,7 +264,12 @@ public class GroovyImportOptimizer implements ImportOptimizer {
TObjectIntHashMap<String> classCountMap = new TObjectIntHashMap<String>();
for (String importedClass : importedClasses) {
if (implicitlyImported.contains(importedClass) || innerClasses.contains(importedClass)) continue;
if (implicitlyImported.contains(importedClass) ||
innerClasses.contains(importedClass) ||
aliased.containsKey(importedClass) ||
annotations.containsKey(importedClass)) {
continue;
}
final String packageName = StringUtil.getPackageName(importedClass);
@@ -286,7 +278,10 @@ public class GroovyImportOptimizer implements ImportOptimizer {
}
for (String importedMember : staticallyImportedMembers) {
if (aliased.containsKey(importedMember) || annotations.containsKey(importedMember)) continue;
final String className = StringUtil.getPackageName(importedMember);
if (!classCountMap.containsKey(className)) classCountMap.put(className, 0);
classCountMap.increment(className);
}
@@ -295,8 +290,13 @@ public class GroovyImportOptimizer implements ImportOptimizer {
final List<GrImportStatement> result = new ArrayList<GrImportStatement>();
packageCountMap.forEachEntry(new TObjectIntProcedure<String>() {
public boolean execute(String s, int i) {
if (i >= settings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND) {
result.add(factory.createImportStatementFromText(s, false, true, null));
if (i >= settings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND || settings.PACKAGES_TO_USE_IMPORT_ON_DEMAND.contains(s)) {
final GrImportStatement imp = factory.createImportStatementFromText(s, false, true, null);
String annos = annotations.get(s + ".*");
if (annos != null) {
imp.getAnnotationList().replace(factory.createModifierList(annos));
}
result.add(imp);
final PsiPackage aPackage = JavaPsiFacade.getInstance(myFile.getProject()).findPackage(s);
if (aPackage != null) {
for (PsiClass clazz : aPackage.getClasses(myFile.getResolveScope())) {
@@ -311,7 +311,12 @@ public class GroovyImportOptimizer implements ImportOptimizer {
classCountMap.forEachEntry(new TObjectIntProcedure<String>() {
public boolean execute(String s, int i) {
if (i >= settings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) {
result.add(factory.createImportStatementFromText(s, true, true, null));
final GrImportStatement imp = factory.createImportStatementFromText(s, true, true, null);
String annos = annotations.get(s + ".*");
if (annos != null) {
imp.getAnnotationList().replace(factory.createModifierList(annos));
}
result.add(imp);
}
return true;
}
@@ -320,43 +325,45 @@ public class GroovyImportOptimizer implements ImportOptimizer {
List<GrImportStatement> explicated = CollectionFactory.arrayList();
for (String importedClass : importedClasses) {
final String parentName = StringUtil.getPackageName(importedClass);
if (packageCountMap.get(parentName) >= settings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND) continue;
if (implicitlyImported.contains(importedClass) &&
!onDemandImportedSimpleClassNames.contains(StringUtil.getShortName(importedClass))) {
continue;
if (!annotations.containsKey(importedClass) && !aliased.containsKey(importedClass)) {
if (packageCountMap.get(parentName) >= settings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND ||
settings.PACKAGES_TO_USE_IMPORT_ON_DEMAND.contains(parentName)) {
continue;
}
if (implicitlyImported.contains(importedClass) &&
!onDemandImportedSimpleClassNames.contains(StringUtil.getShortName(importedClass))) {
continue;
}
}
explicated.add(factory.createImportStatementFromText(importedClass, false, false, null));
final GrImportStatement imp = factory.createImportStatementFromText(importedClass, false, false, null);
String annos = annotations.get(importedClass);
if (annos != null) {
imp.getAnnotationList().replace(factory.createModifierList(annos));
}
explicated.add(imp);
}
for (String importedMember : staticallyImportedMembers) {
final String className = StringUtil.getPackageName(importedMember);
if (classCountMap.get(className) >= settings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) continue;
if (!annotations.containsKey(importedMember) && !aliased.containsKey(importedMember)) {
if (classCountMap.get(className) >= settings.NAMES_COUNT_TO_USE_IMPORT_ON_DEMAND) continue;
}
result.add(factory.createImportStatementFromText(importedMember, true, false, null));
}
final Comparator<GrImportStatement> comparator = new Comparator<GrImportStatement>() {
public int compare(GrImportStatement statement1, GrImportStatement statement2) {
if (settings.LAYOUT_STATIC_IMPORTS_SEPARATELY) {
if (statement1.isStatic() && !statement2.isStatic()) return 1;
if (statement2.isStatic() && !statement1.isStatic()) return -1;
for (GrImportStatement anImport : usedImports) {
if (anImport.isAliasedImport() || isAnnotatedImport(anImport)) {
if (anImport.isStatic()) {
result.add(anImport);
}
if (!statement1.isStatic() && !statement2.isStatic()) {
if (isImportToJavaOrJavax(statement1) && !isImportToJavaOrJavax(statement2)) return 1;
if (!isImportToJavaOrJavax(statement1) && isImportToJavaOrJavax(statement2)) return -1;
else {
explicated.add(anImport);
}
final GrCodeReferenceElement ref1 = statement1.getImportReference();
final GrCodeReferenceElement ref2 = statement2.getImportReference();
String name1 = ref1 != null ? PsiUtil.getQualifiedReferenceText(ref1) : null;
String name2 = ref2 != null ? PsiUtil.getQualifiedReferenceText(ref2) : null;
if (name1 == null) return name2 == null ? 0 : -1;
if (name2 == null) return 1;
return name1.compareTo(name2);
}
};
}
final Comparator<GrImportStatement> comparator = getComparator(settings);
Collections.sort(result, comparator);
Collections.sort(explicated, comparator);
@@ -364,4 +371,36 @@ public class GroovyImportOptimizer implements ImportOptimizer {
return explicated.toArray(new GrImportStatement[explicated.size()]);
}
}
private static boolean isAnnotatedImport(GrImportStatement anImport) {
return !StringUtil.isEmptyOrSpaces(anImport.getAnnotationList().getText());
}
public static Comparator<GrImportStatement> getComparator(final CodeStyleSettings settings) {
return new Comparator<GrImportStatement>() {
public int compare(GrImportStatement statement1, GrImportStatement statement2) {
if (settings.LAYOUT_STATIC_IMPORTS_SEPARATELY) {
if (statement1.isStatic() && !statement2.isStatic()) return 1;
if (statement2.isStatic() && !statement1.isStatic()) return -1;
}
final GrCodeReferenceElement ref1 = statement1.getImportReference();
final GrCodeReferenceElement ref2 = statement2.getImportReference();
String name1 = ref1 != null ? PsiUtil.getQualifiedReferenceText(ref1) : null;
String name2 = ref2 != null ? PsiUtil.getQualifiedReferenceText(ref2) : null;
if (name1 == null) return name2 == null ? 0 : -1;
if (name2 == null) return 1;
return name1.compareTo(name2);
}
};
}
@Nullable
private static String getImportReferenceText(GrImportStatement statement) {
GrCodeReferenceElement importReference = statement.getImportReference();
if (importReference != null) {
return statement.getText().substring(importReference.getStartOffsetInParent());
}
return null;
}
}
@@ -28,6 +28,7 @@ import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocMemberReference;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocReferenceElement;
import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocTag;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
@@ -64,6 +65,8 @@ public abstract class GroovyPsiElementFactory implements JVMElementFactory {
public abstract GrBlockStatement createBlockStatementFromText(String text, @Nullable PsiElement context);
public abstract GrModifierList createModifierList(String text);
public static GroovyPsiElementFactory getInstance(Project project) {
return ServiceManager.getService(project, GroovyPsiElementFactory.class);
}
@@ -17,12 +17,18 @@
package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.extapi.psi.PsiFileBase;
import com.intellij.lang.ASTNode;
import com.intellij.lang.FileASTNode;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.psi.*;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.FileViewProvider;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.codeStyle.CodeStyleSettings;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.PackageEntry;
import com.intellij.psi.codeStyle.PackageEntryTable;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IFileElementType;
import com.intellij.reference.SoftReference;
import com.intellij.util.IncorrectOperationException;
@@ -31,7 +37,10 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.*;
import org.jetbrains.plugins.groovy.lang.psi.GrControlFlowOwner;
import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrTopLevelDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
@@ -41,6 +50,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMe
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.GrTopStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.impl.ControlFlowBuilder;
@@ -48,6 +58,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil.*;
/**
* @author ilyas
*/
@@ -135,43 +147,40 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi
}
public void removeImport(GrImportStatement importStatement) throws IncorrectOperationException {
PsiElement before = importStatement.getPrevSibling();
while (before instanceof PsiWhiteSpace || hasElementType(before, GroovyTokenTypes.mNLS)) {
PsiElement before = importStatement;
while (isWhiteSpace(before.getPrevSibling())) {
before = before.getPrevSibling();
}
PsiElement rangeStart = importStatement;
if (before != null && !(before instanceof PsiImportStatement) && before != importStatement.getPrevSibling()) {
rangeStart = before.getNextSibling();
final PsiElement el = addBefore(GroovyPsiElementFactory.getInstance(getProject()).createLineTerminator(2), rangeStart);
rangeStart=el.getNextSibling();
if (hasElementType(before.getPrevSibling(), GroovyTokenTypes.mSEMI)) before = before.getPrevSibling();
if (isWhiteSpace(before.getPrevSibling())) before = before.getPrevSibling();
PsiElement after = importStatement;
if (isWhiteSpace(after.getNextSibling())) after = after.getNextSibling();
if (hasElementType(after.getNextSibling(), GroovyTokenTypes.mSEMI)) after = after.getNextSibling();
while (isWhiteSpace(after.getNextSibling())) after = after.getNextSibling();
if (before == null) before = importStatement;
PsiElement anchor_before = before.getPrevSibling();
PsiElement anchor_after = after.getNextSibling();
if (before == after) {
importStatement.delete();
}
else {
deleteChildRange(before, after);
}
PsiElement rangeEnd = importStatement;
while (true) {
final PsiElement next = rangeEnd.getNextSibling();
if (!(next instanceof PsiWhiteSpace) && !hasElementType(next, GroovyTokenTypes.mSEMI)) {
break;
}
rangeEnd = next;
if (anchor_before instanceof GrImportStatement && anchor_after instanceof GrImportStatement) {
addLineFeedAfter((GrImportStatement)anchor_before);
}
final PsiElement last = hasElementType(rangeEnd.getNextSibling(), GroovyTokenTypes.mNLS) ? rangeEnd.getNextSibling() : rangeEnd;
if (rangeStart != null && last != null) {
deleteChildRange(rangeStart, last);
else if (anchor_before != null && anchor_after != null) {
String text = anchor_after instanceof GrTopStatement && anchor_before instanceof GrTopStatement ? "\n\n" : "\n";
getNode().addLeaf(GroovyTokenTypes.mNLS, text, anchor_after.getNode());
}
}
private static boolean hasElementType(PsiElement next, final IElementType type) {
if (next == null) {
return false;
}
final ASTNode astNode = next.getNode();
if (astNode != null && astNode.getElementType() == type) {
return true;
}
return false;
}
public void removeElements(PsiElement[] elements) throws IncorrectOperationException {
for (PsiElement element : elements) {
if (element.isValid()) {
@@ -246,8 +255,108 @@ public abstract class GroovyFileBaseImpl extends PsiFileBase implements GroovyFi
@Override
public void deleteChildRange(PsiElement first, PsiElement last) throws IncorrectOperationException {
if (last instanceof GrTopStatement) {
PsiImplUtil.deleteStatementTail(this, last);
deleteStatementTail(this, last);
}
super.deleteChildRange(first, last);
}
protected void addLineFeedBefore(GrImportStatement result) {
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings();
final PackageEntryTable layoutTable = settings.IMPORT_LAYOUT_TABLE;
final PackageEntry[] entries = layoutTable.getEntries();
PsiElement prev = result.getPrevSibling();
while (isWhiteSpace(prev)) {
prev = prev.getPrevSibling();
}
if (hasElementType(prev, GroovyTokenTypes.mSEMI)) prev = prev.getPrevSibling();
if (isWhiteSpace(prev)) prev = prev.getPrevSibling();
if (prev instanceof GrImportStatement) {
final int idx_before = getPackageEntryIdx(entries, (GrImportStatement)prev);
final int idx = getPackageEntryIdx(entries, result);
final int spaceCount = getMaxSpaceCount(entries, idx_before, idx);
//skip space and semicolon after import
if (isWhiteSpace(prev.getNextSibling()) && hasElementType(prev.getNextSibling().getNextSibling(), GroovyTokenTypes.mSEMI)) prev = prev.getNextSibling().getNextSibling();
final FileASTNode node = getNode();
while (isWhiteSpace(prev.getNextSibling())) {
node.removeChild(prev.getNextSibling().getNode());
}
node.addLeaf(GroovyTokenTypes.mNLS, StringUtil.repeat("\n", spaceCount + 1), result.getNode());
}
}
protected void addLineFeedAfter(GrImportStatement result) {
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings();
final PackageEntryTable layoutTable = settings.IMPORT_LAYOUT_TABLE;
final PackageEntry[] entries = layoutTable.getEntries();
PsiElement next = result.getNextSibling();
if (isWhiteSpace(next)) next = next.getNextSibling();
if (hasElementType(next, GroovyTokenTypes.mSEMI)) next = next.getNextSibling();
while (isWhiteSpace(next)) {
next = next.getNextSibling();
}
if (next instanceof GrImportStatement) {
final int idx_after = getPackageEntryIdx(entries, (GrImportStatement)next);
final int idx = getPackageEntryIdx(entries, result);
final int spaceCount = getMaxSpaceCount(entries, idx, idx_after);
final FileASTNode node = getNode();
while (isWhiteSpace(next.getPrevSibling())) {
node.removeChild(next.getPrevSibling().getNode());
}
node.addLeaf(GroovyTokenTypes.mNLS, StringUtil.repeat("\n", spaceCount + 1), next.getNode());
}
}
protected static int getPackageEntryIdx(PackageEntry[] entries, GrImportStatement statement) {
final GrCodeReferenceElement reference = statement.getImportReference();
if (reference == null) return -1;
final String packageName = StringUtil.getPackageName(reference.getCanonicalText());
final boolean isStatic = statement.isStatic();
int best = -1;
int allOtherStatic = -1;
int allOther = -1;
PackageEntry bestEntry = null;
for (int i = 0, length = entries.length; i < length; i++) {
PackageEntry entry = entries[i];
if (entry.isBetterMatchForPackageThan(bestEntry, packageName, isStatic)) {
best = i;
bestEntry = entry;
}
else if (entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY) {
allOtherStatic = i;
}
else if (entry == PackageEntry.ALL_OTHER_IMPORTS_ENTRY) {
allOther = i;
}
}
if (best >= 0) return best;
if (isStatic && allOtherStatic != -1) return allOtherStatic;
return allOther;
}
private static int getMaxSpaceCount(PackageEntry[] entries, int b1, int b2) {
int start = Math.min(b1, b2);
int end = Math.max(b1, b2);
int max = 0;
int cur = 0;
for (int i = start; i < end; i++) {
if (entries[i] == PackageEntry.BLANK_LINE_ENTRY) {
cur++;
}
else {
max = Math.max(max, cur);
cur = 0;
}
}
max = Math.max(max, cur);
return max;
}
}
@@ -18,12 +18,9 @@ package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.CodeStyleManager;
import com.intellij.psi.codeStyle.CodeStyleSettingsManager;
import com.intellij.psi.codeStyle.*;
import com.intellij.psi.impl.ElementBase;
import com.intellij.psi.scope.DelegatingScopeProcessor;
import com.intellij.psi.scope.PsiScopeProcessor;
@@ -38,6 +35,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.GroovyFileType;
import org.jetbrains.plugins.groovy.GroovyIcons;
import org.jetbrains.plugins.groovy.extensions.GroovyScriptTypeDetector;
import org.jetbrains.plugins.groovy.lang.editor.GroovyImportOptimizer;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
@@ -61,11 +59,10 @@ import org.jetbrains.plugins.groovy.lang.resolve.processors.ClassHint;
import javax.swing.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import static org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil.isImportToJavaOrJavax;
/**
* Implements all abstractions related to Groovy file
*
@@ -193,7 +190,7 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
PsiElement lastParent,
PsiElement place,
PsiScopeProcessor importProcessor,
GrImportStatement[] importStatements,
GrImportStatement[] importStatements,
boolean shouldProcessOnDemand) {
for (int i = importStatements.length - 1; i >= 0; i--) {
final GrImportStatement imp = importStatements[i];
@@ -324,11 +321,9 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
public GrImportStatement addImportForClass(PsiClass aClass) {
try {
// Calculating position
Project project = aClass.getProject();
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(project);
GroovyPsiElementFactory factory = GroovyPsiElementFactory.getInstance(getProject());
GrImportStatement importStatement = factory.createImportStatementFromText(aClass.getQualifiedName(), false, false, null);
PsiElement anchor = getAnchorToInsertImportAfter();
return (GrImportStatement)addAfter(importStatement, anchor);
return addImport(importStatement);
}
catch (IncorrectOperationException e) {
LOG.error(e);
@@ -337,81 +332,57 @@ public class GroovyFileImpl extends GroovyFileBaseImpl implements GroovyFile {
}
@Nullable
private PsiElement getAnchorToInsertImportAfter() {
private PsiElement getAnchorToInsertImportAfter(GrImportStatement statement) {
final CodeStyleSettings settings = CodeStyleSettingsManager.getInstance(getProject()).getCurrentSettings();
final PackageEntryTable layoutTable = settings.IMPORT_LAYOUT_TABLE;
final PackageEntry[] entries = layoutTable.getEntries();
GrImportStatement[] importStatements = getImportStatements();
if (importStatements.length > 0) {
return importStatements[importStatements.length - 1];
}
else if (getPackageDefinition() != null) {
return getPackageDefinition();
}
else if (getShellComment() != null) {
if (importStatements.length == 0) {
final GrPackageDefinition definition = getPackageDefinition();
if (definition != null) {
return definition;
}
return getShellComment();
}
return null;
}
final Comparator<GrImportStatement> comparator = GroovyImportOptimizer.getComparator(settings);
final int idx = getPackageEntryIdx(entries, statement);
PsiElement anchor = null;
for (GrImportStatement importStatement : importStatements) {
final int i = getPackageEntryIdx(entries, importStatement);
if (i < idx) {
anchor = importStatement;
}
else if (i > idx) {
break;
}
else if (comparator.compare(statement, importStatement) > 0) {
anchor = importStatement;
}
else {
break;
}
}
if (anchor == null) anchor = getPackageDefinition();
if (anchor == null) anchor = getShellComment();
if (anchor == null && importStatements.length > 0) anchor = importStatements[0].getPrevSibling();
return anchor;
}
public GrImportStatement addImport(GrImportStatement statement) throws IncorrectOperationException {
PsiElement anchor = getAnchorToInsertImportAfter();
PsiElement anchor = getAnchorToInsertImportAfter(statement);
final PsiElement result = addAfter(statement, anchor);
if (anchor != null) {
int lineFeedCount = 0;
if (isAddLineFeed(statement, anchor)) {
lineFeedCount++;
}
final PsiElement prev = result.getPrevSibling();
if (prev instanceof PsiWhiteSpace) {
lineFeedCount += StringUtil.getOccurrenceCount(prev.getText(), '\n');
}
if (lineFeedCount > 0) {
getNode().addLeaf(GroovyTokenTypes.mNLS, StringUtil.repeatSymbol('\n', lineFeedCount), result.getNode());
}
if (prev instanceof PsiWhiteSpace) {
prev.delete();
}
}
GrImportStatement importStatement = (GrImportStatement)result;
PsiElement next = importStatement.getNextSibling();
if (next != null) {
ASTNode node = next.getNode();
if (node != null && GroovyTokenTypes.mNLS == node.getElementType()) {
next.replace(GroovyPsiElementFactory.getInstance(statement.getProject()).createLineTerminator(2));
}
}
return importStatement;
}
private static boolean isAddLineFeed(GrImportStatement statement, PsiElement anchor) {
if (!(anchor instanceof GrImportStatement)) {
return true;
}
final GrImportStatement _anchor = (GrImportStatement)anchor;
//aliases
if (statement.isAliasedImport() || _anchor.isAliasedImport()) {
return _anchor.isAliasedImport() ^ statement.isAliasedImport();
}
//static imports
if (CodeStyleSettingsManager.getSettings(statement.getProject()).LAYOUT_STATIC_IMPORTS_SEPARATELY) {
if (statement.isStatic() || _anchor.isStatic()) {
return statement.isStatic() ^ _anchor.isStatic();
}
}
//imports to std lib
if (isImportToJavaOrJavax(statement) || isImportToJavaOrJavax(_anchor)) {
return isImportToJavaOrJavax(statement) ^ isImportToJavaOrJavax(_anchor);
}
return false;
final GrImportStatement gImport = (GrImportStatement)result;
addLineFeedBefore(gImport);
addLineFeedAfter(gImport);
return gImport;
}
public boolean isScript() {
@@ -41,6 +41,7 @@ import org.jetbrains.plugins.groovy.lang.groovydoc.psi.api.GrDocTag;
import org.jetbrains.plugins.groovy.lang.psi.*;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifier;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.GrModifierList;
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.modifiers.annotation.GrAnnotation;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.*;
@@ -685,6 +686,12 @@ public class GroovyPsiElementFactoryImpl extends GroovyPsiElementFactory {
return (GrBlockStatement)branch;
}
@Override
public GrModifierList createModifierList(String text) {
final GrMethod method = createMethodFromText(text + " void foo()");
return method.getModifierList();
}
public GrImportStatement createImportStatementFromText(String qName, boolean isStatic, boolean isOnDemand, String alias) {
final String text = "import " + (isStatic ? "static " : "") + qName + (isOnDemand ? ".*" : "") +
(alias != null && alias.length() > 0 ? " as " + alias : "");
@@ -30,6 +30,7 @@ import com.intellij.psi.impl.source.tree.AstBufferUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.psi.util.MethodSignature;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiTreeUtil;
@@ -65,8 +66,6 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameter;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrReflectedMethod;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrTypeElement;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.arithmetic.GrAdditiveExpressionImpl;
@@ -691,15 +690,20 @@ public class PsiImplUtil {
return type;
}
public static boolean isImportToJavaOrJavax(GrImportStatement statement) {
final GrCodeReferenceElement ref = statement.getImportReference();
if (ref==null) return false;
final String text = ref.getText();
return text.startsWith("java.") || text.startsWith("javax.");
}
public static boolean isWhiteSpace(PsiElement element) {
return element != null && TokenSets.WHITE_SPACES_SET.contains(element.getNode().getElementType());
return hasElementType(element, TokenSets.WHITE_SPACES_SET);
}
public static boolean hasElementType(PsiElement next, final IElementType type) {
if (next == null) return false;
final ASTNode astNode = next.getNode();
return astNode != null && astNode.getElementType() == type;
}
public static boolean hasElementType(PsiElement next, final TokenSet set) {
if (next == null) return false;
final ASTNode astNode = next.getNode();
return astNode != null && set.contains(astNode.getElementType());
}
}
@@ -1,286 +1,286 @@
/*
* Copyright 2000-2010 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.
* 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 org.jetbrains.plugins.groovy.completion;
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.completion.StaticallyImportable
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.plugins.groovy.util.TestUtils
/**
* @author Maxim.Medvedev
*/
public class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCase {
private boolean old;
@Override
protected String getBasePath() {
return TestUtils.getTestDataPath() + "groovy/completion/classNameCompletion";
}
private void doTest() throws Exception {
addClassToProject("a", "FooBar");
myFixture.configureByFile(getTestName(false) + ".groovy");
complete()
myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
}
private void addClassToProject(@Nullable String packageName, @NotNull String name) throws IOException {
myFixture.addClass("package $packageName; public class $name {}");
}
public void testInFieldDeclaration() throws Exception {doTest();}
public void testInParameter() throws Exception {doTest();}
public void testInImport() throws Exception {doTest();}
public void testWhenClassExistsInSamePackage() throws Exception {
addClassToProject("a", "FooBar")
myFixture.configureByFile(getTestName(false) + ".groovy")
complete()
def lookup = LookupManager.getActiveLookup(myFixture.editor)
lookup.currentItem = lookup.items[1]
myFixture.type('\n')
myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
}
public void testInComment() throws Exception {doTest();}
public void testInTypeElementPlace() throws Exception {doTest();}
public void testWhenImportExists() throws Exception{doTest();}
public void testFinishByDot() throws Exception{
addClassToProject("a", "FooBar");
myFixture.configureByText("a.groovy", "FB<caret>a")
complete()
myFixture.type '.'.charAt(0)
myFixture.checkResult "a.FooBar.<caret>a"
}
private LookupElement[] complete() {
myFixture.complete(CompletionType.BASIC, 2)
}
public void testDelegateBasicToClassName() throws Exception{
addClassToProject("a", "FooBarGooDoo");
myFixture.configureByText("a.groovy", "FBGD<caret>a")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.type '.'.charAt(0)
myFixture.checkResult "a.FooBarGooDoo.<caret>a"
}
public void testDelegateBasicToClassNameAutoinsert() throws Exception{
addClassToProject("a", "FooBarGooDoo");
myFixture.configureByText("a.groovy", "FBGD<caret>")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.checkResult "a.FooBarGooDoo<caret>"
}
public void testImportedStaticMethod() throws Exception {
myFixture.addFileToProject("b.groovy", """
class Foo {
static def abcmethod1(int a) {}
static def abcmethod2(int a) {}
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcme<caret>
}""")
def item = complete()[0]
LookupElementPresentation presentation = renderElement(item)
assert "Foo.abcmethod1" == presentation.itemText
assert presentation.tailText == "(int a)"
((StaticallyImportable) item).shouldBeImported = true
myFixture.type('\n')
myFixture.checkResult """import static Foo.abcmethod1
def foo() {
abcmethod1(<caret>)
}"""
}
public void testImportedStaticField() throws Exception {
myFixture.addFileToProject("b.groovy", """
class Foo {
static def abcfield1
static def abcfield2
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcfi<caret>
}""")
def item = complete()[0]
((StaticallyImportable) item).shouldBeImported = true
myFixture.type('\n')
myFixture.checkResult """import static Foo.abcfield1
def foo() {
abcfield1<caret>
}"""
}
public void testImportedInterfaceConstant() throws Exception {
myFixture.addFileToProject("b.groovy", """
interface Foo {
static def abcfield1 = 2
static def abcfield2 = 3
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcfi<caret>
}""")
def item = complete()[0]
((StaticallyImportable) item).shouldBeImported = true
myFixture.type('\n')
myFixture.checkResult """import static Foo.abcfield1
def foo() {
abcfield1<caret>
}"""
}
public void testQualifiedStaticMethod() throws Exception {
myFixture.addFileToProject("foo/b.groovy", """package foo
class Foo {
static def abcmethod(int a) {}
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcme<caret>
}""")
complete()
myFixture.checkResult """import foo.Foo
def foo() {
Foo.abcmethod(<caret>)
}"""
}
public void testQualifiedStaticMethodIfThereAreAlreadyStaticImportsFromThatClass() throws Exception {
myFixture.addFileToProject("foo/b.groovy", """package foo
class Foo {
static def abcMethod() {}
static def anotherMethod() {}
}""")
myFixture.configureByText("a.groovy", """
import static foo.Foo.anotherMethod
anotherMethod()
abcme<caret>x""")
def element = assertOneElement(complete()[0])
LookupElementPresentation presentation = renderElement(element)
assert "abcMethod" == presentation.itemText
assert presentation.tailText == "() in Foo (foo)"
myFixture.type('\t')
myFixture.checkResult """
import static foo.Foo.anotherMethod
import static foo.Foo.abcMethod
anotherMethod()
abcMethod()<caret>"""
}
private LookupElementPresentation renderElement(LookupElement element) {
return LookupElementPresentation.renderElement(element)
}
public void testNewClassName() {
addClassToProject("foo", "Fxoo")
myFixture.configureByText("a.groovy", "new Fxo<caret>\n")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.checkResult """import foo.Fxoo
new Fxoo()<caret>\n"""
}
public void testNewImportedClassName() {
myFixture.configureByText("a.groovy", "new ArrayIndexOut<caret>\n")
myFixture.completeBasic()
myFixture.checkResult "new ArrayIndexOutOfBoundsException(<caret>)\n"
}
public void testOnlyAnnotationsAfterAt() {
myFixture.addClass "class AbcdClass {}; @interface AbcdAnno {}"
myFixture.configureByText "a.groovy", "@Abcd<caret>"
complete()
assert myFixture.lookupElementStrings[0] == 'AbcdAnno'
}
public void testOnlyExceptionsInCatch() {
myFixture.addClass "class AbcdClass {}; class AbcdException extends Throwable {}"
myFixture.configureByText "a.groovy", "try {} catch (Abcd<caret>"
complete()
assert myFixture.lookupElementStrings[0] == 'AbcdException'
}
public void testClassNameInMultilineString() {
myFixture.configureByText "a.groovy", 'def s = """a\nAIOOBE<caret>\na"""'
complete()
myFixture.checkResult 'def s = """a\njava.lang.ArrayIndexOutOfBoundsException<caret>\na"""'
}
public void testDoubleClass() {
myFixture.addClass "package foo; public class Zooooooo {}"
myFixture.configureByText("a.groovy", """import foo.Zooooooo
Zoooo<caret>x""")
assertOneElement(myFixture.completeBasic())
}
public void testClassOnlyOnce() {
myFixture.addClass('class FooBarGoo {}')
myFixture.configureByText('a.groovy', 'FoBaGo<caret>')
assert !complete()
myFixture.checkResult('''FooBarGoo<caret>''')
}
public void testMethodFromTheSameClass() {
myFixture.configureByText("a.groovy", """
class A {
static void foo() {}
static void goo() {
f<caret>
}
}
""")
def items = complete()
def fooItem = items.find { renderElement(it).itemText == 'foo' }
LookupManager.getActiveLookup(myFixture.editor).currentItem = fooItem
myFixture.type '\n'
myFixture.checkResult '''
class A {
static void foo() {}
static void goo() {
foo()<caret>
}
}
'''
}
}
/*
* Copyright 2000-2010 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.
* 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 org.jetbrains.plugins.groovy.completion;
import com.intellij.codeInsight.completion.CompletionType
import com.intellij.codeInsight.completion.StaticallyImportable
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementPresentation
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.annotations.NotNull
import org.jetbrains.annotations.Nullable
import org.jetbrains.plugins.groovy.util.TestUtils
/**
* @author Maxim.Medvedev
*/
public class GroovyClassNameCompletionTest extends LightCodeInsightFixtureTestCase {
private boolean old;
@Override
protected String getBasePath() {
return TestUtils.getTestDataPath() + "groovy/completion/classNameCompletion";
}
private void doTest() throws Exception {
addClassToProject("a", "FooBar");
myFixture.configureByFile(getTestName(false) + ".groovy");
complete()
myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
}
private void addClassToProject(@Nullable String packageName, @NotNull String name) throws IOException {
myFixture.addClass("package $packageName; public class $name {}");
}
public void testInFieldDeclaration() throws Exception {doTest();}
public void testInParameter() throws Exception {doTest();}
public void testInImport() throws Exception {doTest();}
public void testWhenClassExistsInSamePackage() throws Exception {
addClassToProject("a", "FooBar")
myFixture.configureByFile(getTestName(false) + ".groovy")
complete()
def lookup = LookupManager.getActiveLookup(myFixture.editor)
lookup.currentItem = lookup.items[1]
myFixture.type('\n')
myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
}
public void testInComment() throws Exception {doTest();}
public void testInTypeElementPlace() throws Exception {doTest();}
public void testWhenImportExists() throws Exception{doTest();}
public void testFinishByDot() throws Exception{
addClassToProject("a", "FooBar");
myFixture.configureByText("a.groovy", "FB<caret>a")
complete()
myFixture.type '.'.charAt(0)
myFixture.checkResult "a.FooBar.<caret>a"
}
private LookupElement[] complete() {
myFixture.complete(CompletionType.BASIC, 2)
}
public void testDelegateBasicToClassName() throws Exception{
addClassToProject("a", "FooBarGooDoo");
myFixture.configureByText("a.groovy", "FBGD<caret>a")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.type '.'.charAt(0)
myFixture.checkResult "a.FooBarGooDoo.<caret>a"
}
public void testDelegateBasicToClassNameAutoinsert() throws Exception{
addClassToProject("a", "FooBarGooDoo");
myFixture.configureByText("a.groovy", "FBGD<caret>")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.checkResult "a.FooBarGooDoo<caret>"
}
public void testImportedStaticMethod() throws Exception {
myFixture.addFileToProject("b.groovy", """
class Foo {
static def abcmethod1(int a) {}
static def abcmethod2(int a) {}
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcme<caret>
}""")
def item = complete()[0]
LookupElementPresentation presentation = renderElement(item)
assert "Foo.abcmethod1" == presentation.itemText
assert presentation.tailText == "(int a)"
((StaticallyImportable) item).shouldBeImported = true
myFixture.type('\n')
myFixture.checkResult """import static Foo.abcmethod1
def foo() {
abcmethod1(<caret>)
}"""
}
public void testImportedStaticField() throws Exception {
myFixture.addFileToProject("b.groovy", """
class Foo {
static def abcfield1
static def abcfield2
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcfi<caret>
}""")
def item = complete()[0]
((StaticallyImportable) item).shouldBeImported = true
myFixture.type('\n')
myFixture.checkResult """import static Foo.abcfield1
def foo() {
abcfield1<caret>
}"""
}
public void testImportedInterfaceConstant() throws Exception {
myFixture.addFileToProject("b.groovy", """
interface Foo {
static def abcfield1 = 2
static def abcfield2 = 3
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcfi<caret>
}""")
def item = complete()[0]
((StaticallyImportable) item).shouldBeImported = true
myFixture.type('\n')
myFixture.checkResult """import static Foo.abcfield1
def foo() {
abcfield1<caret>
}"""
}
public void testQualifiedStaticMethod() throws Exception {
myFixture.addFileToProject("foo/b.groovy", """package foo
class Foo {
static def abcmethod(int a) {}
}""")
myFixture.configureByText("a.groovy", """def foo() {
abcme<caret>
}""")
complete()
myFixture.checkResult """import foo.Foo
def foo() {
Foo.abcmethod(<caret>)
}"""
}
public void testQualifiedStaticMethodIfThereAreAlreadyStaticImportsFromThatClass() throws Exception {
myFixture.addFileToProject("foo/b.groovy", """package foo
class Foo {
static def abcMethod() {}
static def anotherMethod() {}
}""")
myFixture.configureByText("a.groovy", """
import static foo.Foo.anotherMethod
anotherMethod()
abcme<caret>x""")
def element = assertOneElement(complete()[0])
LookupElementPresentation presentation = renderElement(element)
assert "abcMethod" == presentation.itemText
assert presentation.tailText == "() in Foo (foo)"
myFixture.type('\t')
myFixture.checkResult """\
import static foo.Foo.abcMethod
import static foo.Foo.anotherMethod
anotherMethod()
abcMethod()<caret>"""
}
private LookupElementPresentation renderElement(LookupElement element) {
return LookupElementPresentation.renderElement(element)
}
public void testNewClassName() {
addClassToProject("foo", "Fxoo")
myFixture.configureByText("a.groovy", "new Fxo<caret>\n")
myFixture.complete(CompletionType.BASIC, 2)
myFixture.checkResult """import foo.Fxoo
new Fxoo()<caret>\n"""
}
public void testNewImportedClassName() {
myFixture.configureByText("a.groovy", "new ArrayIndexOut<caret>\n")
myFixture.completeBasic()
myFixture.checkResult "new ArrayIndexOutOfBoundsException(<caret>)\n"
}
public void testOnlyAnnotationsAfterAt() {
myFixture.addClass "class AbcdClass {}; @interface AbcdAnno {}"
myFixture.configureByText "a.groovy", "@Abcd<caret>"
complete()
assert myFixture.lookupElementStrings[0] == 'AbcdAnno'
}
public void testOnlyExceptionsInCatch() {
myFixture.addClass "class AbcdClass {}; class AbcdException extends Throwable {}"
myFixture.configureByText "a.groovy", "try {} catch (Abcd<caret>"
complete()
assert myFixture.lookupElementStrings[0] == 'AbcdException'
}
public void testClassNameInMultilineString() {
myFixture.configureByText "a.groovy", 'def s = """a\nAIOOBE<caret>\na"""'
complete()
myFixture.checkResult 'def s = """a\njava.lang.ArrayIndexOutOfBoundsException<caret>\na"""'
}
public void testDoubleClass() {
myFixture.addClass "package foo; public class Zooooooo {}"
myFixture.configureByText("a.groovy", """import foo.Zooooooo
Zoooo<caret>x""")
assertOneElement(myFixture.completeBasic())
}
public void testClassOnlyOnce() {
myFixture.addClass('class FooBarGoo {}')
myFixture.configureByText('a.groovy', 'FoBaGo<caret>')
assert !complete()
myFixture.checkResult('''FooBarGoo<caret>''')
}
public void testMethodFromTheSameClass() {
myFixture.configureByText("a.groovy", """
class A {
static void foo() {}
static void goo() {
f<caret>
}
}
""")
def items = complete()
def fooItem = items.find { renderElement(it).itemText == 'foo' }
LookupManager.getActiveLookup(myFixture.editor).currentItem = fooItem
myFixture.type '\n'
myFixture.checkResult '''
class A {
static void foo() {}
static void goo() {
foo()<caret>
}
}
'''
}
}
@@ -48,13 +48,27 @@ public class GroovyMoveClassToInnerTest extends GroovyMoveTestBase {
}
public void testInsertInnerClassImport() throws Exception {
CodeStyleSettingsManager.getSettings(myFixture.project).INSERT_INNER_CLASS_IMPORTS = true;
doTest("pack2.A", "pack1.Class1");
final settings = CodeStyleSettingsManager.getSettings(myFixture.project)
def oldValue = settings.INSERT_INNER_CLASS_IMPORTS
settings.INSERT_INNER_CLASS_IMPORTS = true;
try {
doTest("pack2.A", "pack1.Class1");
}
finally {
settings.INSERT_INNER_CLASS_IMPORTS = oldValue
}
}
public void testSimultaneousMove() throws Exception {
CodeStyleSettingsManager.instance.currentSettings.INSERT_INNER_CLASS_IMPORTS = false
doTest("pack2.A", "pack1.Class1", "pack0.Class0");
final settings = CodeStyleSettingsManager.instance.currentSettings
final oldValue = settings.INSERT_INNER_CLASS_IMPORTS
settings.INSERT_INNER_CLASS_IMPORTS = false
try {
doTest("pack2.A", "pack1.Class1", "pack0.Class0");
}
finally {
settings.INSERT_INNER_CLASS_IMPORTS = oldValue
}
}
public void testMoveMultiple1() throws Exception {
@@ -24,8 +24,8 @@ import com.intellij.openapi.fileEditor.impl.TrailingSpacesStripper
import com.intellij.psi.codeStyle.CodeStyleSettings
import com.intellij.psi.codeStyle.CodeStyleSettingsManager
import com.intellij.psi.impl.source.PostprocessReformattingAspect
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl
import org.jetbrains.plugins.groovy.LightGroovyTestCase
import org.jetbrains.plugins.groovy.codeInspection.bugs.GroovyAccessibilityInspection
import org.jetbrains.plugins.groovy.lang.editor.GroovyImportOptimizer
import org.jetbrains.plugins.groovy.util.TestUtils
@@ -33,84 +33,83 @@ import org.jetbrains.plugins.groovy.util.TestUtils
/**
* @author ilyas
*/
public class OptimizeImportsTest extends LightCodeInsightFixtureTestCase {
public class OptimizeImportsTest extends LightGroovyTestCase {
final String basePath = "${TestUtils.testDataPath}optimizeImports/"
@Override
protected String getBasePath() {
return "${TestUtils.testDataPath}optimizeImports/";
}
@Override protected void setUp() {
protected void setUp() {
super.setUp()
CodeInsightSettings.instance.OPTIMIZE_IMPORTS_ON_THE_FLY = true
((CodeInsightTestFixtureImpl)myFixture).canChangeDocumentDuringHighlighting(true)
}
@Override protected void tearDown() {
@Override
protected void tearDown() {
CodeInsightSettings.instance.OPTIMIZE_IMPORTS_ON_THE_FLY = false
super.tearDown()
}
public void testNewline() throws Throwable {
public void testNewline() {
doTest();
}
public void testAliased() throws Throwable {
public void testAliased() {
doTest();
}
public void testSimpleOptimize() throws Throwable {
public void testSimpleOptimize() {
doTest();
}
public void testCommented() throws Throwable {
public void testCommented() {
doTest();
}
public void testOptimizeExists() throws Throwable {
public void testOptimizeExists() {
doTest();
}
public void testOptimizeAlias() throws Throwable {
public void testOptimizeAlias() {
doTest();
}
public void testFoldImports() throws Throwable {
public void testFoldImports() {
doTest();
}
public void testFoldImports2() throws Throwable {
public void testFoldImports2() {
doTest();
}
public void testUntypedCall() throws Throwable {
public void testUntypedCall() {
doTest();
}
public void testFoldImports3() throws Throwable {
public void testFoldImports3() {
doTest();
}
public void testFoldImports4() throws Throwable {
public void testFoldImports4() {
doTest();
}
public void testFoldImports5() throws Throwable {
public void testFoldImports5() {
doTest();
}
public void testFixPoint() throws Throwable {
public void testFixPoint() {
doTest();
}
public void testPreserveImportAnnotations() throws Throwable { doTest(); }
public void testPreserveImportAnnotations() { doTest(); }
public void testUtilListMasked() throws Throwable {
public void testUtilListMasked() {
myFixture.addClass("package java.awt; public class List {}");
doTest();
}
public void testExtraLineFeed() throws Throwable {
public void testExtraLineFeed() {
myFixture.addClass("package groovy.io; public class EncodingAwareBufferedWriter {}");
myFixture.addClass("package groovy.io; public class PlatformLineWriter {}");
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject(getTestName(false) + ".groovy", "foo/bar.groovy"));
@@ -119,37 +118,37 @@ public class OptimizeImportsTest extends LightCodeInsightFixtureTestCase {
myFixture.checkResultByFile(getTestName(false) + ".groovy");
}
public void testSemicolons() throws Throwable {
public void testSemicolons() {
doTest();
}
public void testSameFile() throws Throwable {
public void testSameFile() {
doTest();
}
public void testJavaUtilString() throws Throwable { doTest(); }
public void testJavaUtilString() { doTest(); }
public void testSamePackage() throws Throwable {
public void testSamePackage() {
myFixture.addClass("package foo; public class Bar {}");
myFixture.configureFromExistingVirtualFile(myFixture.copyFileToProject(getTestName(false) + ".groovy", "foo/Foo.groovy"));
doOptimizeImports();
myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
}
public void testQualifiedUsage() throws Throwable {
public void testQualifiedUsage() {
myFixture.addClass("package foo; public class Bar {}");
doTest();
}
public void testFileHeader() throws Throwable {
public void testFileHeader() {
doTest();
}
public void testRemoveImplicitlyImported() throws Throwable { doTest(); }
public void testRemoveImplicitlyDemandImported() throws Throwable { doTest(); }
public void testDontRemoveRedImports() throws Throwable { doTest(); }
public void testRemoveImplicitlyImported() { doTest(); }
public void testRemoveImplicitlyDemandImported() { doTest(); }
public void testDontRemoveRedImports() { doTest(); }
public void testRemoveSamePackaged() throws Throwable {
public void testRemoveSamePackaged() {
myFixture.addClass("package foo.bar; public class Aaaa {}");
myFixture.addClass("package foo.bar; public class Bbbb {}");
myFixture.addClass("package foo.bar; public class Zzzz {}");
@@ -182,7 +181,7 @@ class Fooxx <caret>{
}""");
}
private void doTest() throws Throwable {
private void doTest() {
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).clone();
CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(settings);
settings.CLASS_COUNT_TO_USE_IMPORT_ON_DEMAND = 3;
@@ -235,7 +234,7 @@ class Fooxx <caret>{
myFixture.checkResult "import foo.Foo\n\ndef foo() { \n <caret>Foo f}"
}
public void testUnusedImportsForImportsOnDemand() throws Exception {
public void testUnusedImportsForImportsOnDemand() {
myFixture.enableInspections(new GroovyAccessibilityInspection())
myFixture.testHighlighting(true, false, false, getTestName(false) + ".groovy")
myFixture.checkResultByFile(getTestName(false) + "_after.groovy");
@@ -249,7 +248,7 @@ class Fooxx <caret>{
myFixture.addClass("package test; public class Alias{public static void test(){}}")
myFixture.addClass("package test; public class Alias2{public static void test2(){}}")
myFixture.configureByText('__a.groovy', '''
myFixture.configureByText('__a.groovy', '''\
package pack
@@ -276,12 +275,9 @@ aliased2()
doOptimizeImports()
myFixture.checkResult('''
myFixture.checkResult('''\
package pack
import static test.Alias.test as aliased
import static test.Alias2.test2 as aliased2
import foo.Bar
import foo.Foo
@@ -290,6 +286,8 @@ import java.test2.Test2
import static foo.Bar.foo0
import static java.test.Test.foo
import static test.Alias.test as aliased
import static test.Alias2.test2 as aliased2
new Foo()
new Bar()
@@ -1,9 +1,8 @@
package org.gradle
import java.sql.Connection as Con
import java.sql.Clob as CB
import java.sql.Blob
import java.sql.Clob as CB
import java.sql.Connection as Con
Blob blob = null
CB cb = null
@@ -1,5 +1,4 @@
import javax.swing.JFrame
import javax.swing.*
// preved!
def frame = new JFrame()
@@ -2,6 +2,7 @@
* asdf lsd
*/
import java.sql.Blob
Blob blob = null
@@ -1,5 +1,4 @@
import javax.swing.JDialog
import javax.swing.JTable
import javax.swing.*
def table = new JTable()
def dialog = new JDialog()
@@ -1,6 +1,5 @@
import javax.swing.JButton as JB
import javax.swing.*
import javax.swing.JButton as JB
def frame = new JFrame()
def table = new JTable()
@@ -1,6 +1,5 @@
import javax.swing.JButton as JB
import javax.swing.*
import javax.swing.JButton as JB
def frame = new JFrame()
def table = new JTable()
@@ -1,5 +1,5 @@
import java.security.Policy
import javax.swing.*
import java.security.Policy
def frame = new JFrame()
def table = new JTable()
@@ -1,3 +1,3 @@
import javax.swing.JFrame
import javax.swing.*
def frame = new JFrame()
@@ -1,5 +1,5 @@
import java.util.List
import java.awt.*
import java.util.List
Component a
Container c
@@ -1,7 +1,7 @@
package b;
package b
import b.B
import a.A;
import b.B;
def a = new A().foo();
print a;
@@ -1,5 +1,4 @@
package b;
package b
class B {
def fooB(int i) {
@@ -1,7 +1,6 @@
package b;
package b
import a.A;
import a.A
def a = new A().foo();
print a;
@@ -1,5 +1,4 @@
package b;
package b
class B {
def fooB(int i) {
@@ -1,7 +1,7 @@
package b;
package b
import b.B
import a.A;
import b.B;
def a = new A().foo();
print a;