mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge branch 'master' of git.labs.intellij.net:idea/community
This commit is contained in:
@@ -526,9 +526,12 @@ public class JavaCompletionData extends JavaAwareCompletionData{
|
||||
return;
|
||||
}
|
||||
|
||||
final PsiExpressionStatement expressionStatement = PsiTreeUtil.getParentOfType(position, PsiExpressionStatement.class);
|
||||
if (expressionStatement != null && expressionStatement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) {
|
||||
if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).accepts(expressionStatement)) {
|
||||
PsiStatement statement = PsiTreeUtil.getParentOfType(position, PsiExpressionStatement.class);
|
||||
if (statement == null) {
|
||||
statement = PsiTreeUtil.getParentOfType(position, PsiDeclarationStatement.class);
|
||||
}
|
||||
if (statement != null && statement.getTextRange().getStartOffset() == position.getTextRange().getStartOffset()) {
|
||||
if (!psiElement().withSuperParent(2, PsiSwitchStatement.class).accepts(statement)) {
|
||||
result.addElement(createKeyword(position, PsiKeyword.FINAL));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,11 +103,12 @@ public class OverrideImplementUtil {
|
||||
Map<MethodSignature, PsiMethod> finals = new LinkedHashMap<MethodSignature,PsiMethod>();
|
||||
Map<MethodSignature, PsiMethod> concretes = new LinkedHashMap<MethodSignature,PsiMethod>();
|
||||
|
||||
LOG.assertTrue(aClass.isValid());
|
||||
Collection<HierarchicalMethodSignature> allMethodSigs = aClass.getVisibleSignatures();
|
||||
PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(aClass.getProject()).getResolveHelper();
|
||||
for (HierarchicalMethodSignature signature : allMethodSigs) {
|
||||
PsiMethod method = signature.getMethod();
|
||||
LOG.assertTrue(method.isValid());
|
||||
LOG.assertTrue(method.isValid(), aClass);
|
||||
|
||||
if (method.hasModifierProperty(PsiModifier.STATIC) || !resolveHelper.isAccessible(method, aClass, aClass)) continue;
|
||||
PsiClass hisClass = method.getContainingClass();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.HierarchicalMethodSignatureImpl;
|
||||
@@ -32,6 +33,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import java.util.*;
|
||||
|
||||
public class PsiSuperMethodImplUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiSuperMethodImplUtil");
|
||||
private static final PsiCacheKey<Map<MethodSignature, HierarchicalMethodSignature>, PsiClass> SIGNATURES_KEY = PsiCacheKey
|
||||
.create("SIGNATURES_KEY", new NotNullFunction<PsiClass, Map<MethodSignature, HierarchicalMethodSignature>>() {
|
||||
@NotNull
|
||||
@@ -134,6 +136,7 @@ public class PsiSuperMethodImplUtil {
|
||||
});
|
||||
|
||||
for (PsiMethod method : aClass.getMethods()) {
|
||||
LOG.assertTrue(method.isValid());
|
||||
if (!includePrivates && method.hasModifierProperty(PsiModifier.PRIVATE)) continue;
|
||||
final MethodSignatureBackedByPsiMethod signature = MethodSignatureBackedByPsiMethod.create(method, substitutor, isInRawContext);
|
||||
HierarchicalMethodSignatureImpl newH = new HierarchicalMethodSignatureImpl(signature);
|
||||
@@ -145,6 +148,7 @@ public class PsiSuperMethodImplUtil {
|
||||
}
|
||||
list.add(method);
|
||||
|
||||
LOG.assertTrue(newH.getMethod().isValid());
|
||||
result.put(signature, newH);
|
||||
map.put(signature, newH);
|
||||
}
|
||||
@@ -188,6 +192,7 @@ public class PsiSuperMethodImplUtil {
|
||||
HierarchicalMethodSignatureImpl hierarchicalMethodSignature = entry.getValue();
|
||||
MethodSignature methodSignature = entry.getKey();
|
||||
if (result.get(methodSignature) == null && PsiUtil.isAccessible(hierarchicalMethodSignature.getMethod(), aClass, aClass)) {
|
||||
LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid());
|
||||
result.put(methodSignature, hierarchicalMethodSignature);
|
||||
}
|
||||
}
|
||||
@@ -213,6 +218,7 @@ public class PsiSuperMethodImplUtil {
|
||||
}
|
||||
// just drop an invalid method declaration there - to highlight accordingly
|
||||
else if (!result.containsKey(signature)) {
|
||||
LOG.assertTrue(hierarchicalMethodSignature.getMethod().isValid());
|
||||
result.put(signature, hierarchicalMethodSignature);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
public enum Foo { private Fo<caret> }
|
||||
public enum Foooooo { private Fooo<caret> }
|
||||
+1
-1
@@ -1 +1 @@
|
||||
public enum Foo { private Foo<caret> }
|
||||
public enum Foooooo { private Foooooo<caret> }
|
||||
@@ -0,0 +1,9 @@
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Foooo {
|
||||
|
||||
{
|
||||
for (fin<caret> Object o : new ArrayList())
|
||||
}
|
||||
|
||||
}
|
||||
-6
@@ -1,6 +0,0 @@
|
||||
public class Beda {
|
||||
{
|
||||
Object clsLoader;
|
||||
cL<caret>
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
class Foo {
|
||||
{
|
||||
Object classLoader;
|
||||
Object classBeforeLoader;
|
||||
cL<caret>
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
class Foo {
|
||||
{
|
||||
Object classLoader;
|
||||
Object classLoader2;
|
||||
cL<caret>
|
||||
}
|
||||
|
||||
}
|
||||
+1
-28
@@ -5,7 +5,6 @@
|
||||
package com.intellij.codeInsight.completion;
|
||||
|
||||
import com.intellij.JavaTestUtil;
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.codeInsight.lookup.LookupElement;
|
||||
import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.psi.PsiClass;
|
||||
@@ -68,32 +67,6 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase {
|
||||
checkPreferredItems(0, "getService", "getService", "class");
|
||||
}
|
||||
|
||||
public void testUppercaseMatters() throws Throwable {
|
||||
final int old = CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE;
|
||||
try {
|
||||
CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = CodeInsightSettings.FIRST_LETTER;
|
||||
checkPreferredItems(0, "classLoader", "class", "classBeforeLoader", "clone");
|
||||
}
|
||||
finally {
|
||||
CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = old;
|
||||
}
|
||||
}
|
||||
|
||||
public void testUppercaseMatters2() throws Throwable {
|
||||
final int old = CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE;
|
||||
try {
|
||||
CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = CodeInsightSettings.ALL;
|
||||
checkPreferredItems(0, "classLoader", "classLoader2");
|
||||
}
|
||||
finally {
|
||||
CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE = old;
|
||||
}
|
||||
}
|
||||
|
||||
public void testHonorUppercaseLetters() throws Throwable {
|
||||
checkPreferredItems(0, "clsLoader", "clone", "class");
|
||||
}
|
||||
|
||||
public void testClassStaticMembersInVoidContext() throws Throwable {
|
||||
checkPreferredItems(0, "booleanMethod", "voidMethod", "AN_OBJECT", "BOOLEAN", "class");
|
||||
}
|
||||
@@ -232,4 +205,4 @@ public class NormalCompletionOrderingTest extends CompletionSortingTestCase {
|
||||
checkPreferredItems(0, "Bar9", "Bar1", "Bar2", "Bar3", "Bar4");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+6
-2
@@ -709,8 +709,12 @@ public class NormalCompletionTest extends LightFixtureCompletionTestCase {
|
||||
|
||||
public void testFinalInForLoop() throws Throwable {
|
||||
configure()
|
||||
checkResultByFile(getTestName(false) + ".java")
|
||||
assertOrderedEquals myFixture.lookupElementStrings, 'final'
|
||||
assertStringItems 'final'
|
||||
}
|
||||
|
||||
public void testFinalInForLoop2() throws Throwable {
|
||||
configure()
|
||||
assertStringItems 'final', 'finalize'
|
||||
}
|
||||
|
||||
public void testPrimitiveTypesInForLoop() throws Throwable { doPrimitiveTypeTest() }
|
||||
|
||||
-7
@@ -142,11 +142,4 @@ public class VariablesCompletionTest extends CompletionTestCase {
|
||||
|
||||
assertStringItems(LineTokenizer.tokenize(FileDocumentManager.getInstance().getDocument(result).getCharsSequence(), false));
|
||||
}
|
||||
|
||||
private void assertStringItems(String... strings) {
|
||||
assertNotNull(myItems);
|
||||
for (int i = 0; i < myItems.length; i++) {
|
||||
assertEquals(strings[i], myItems[i].toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,12 @@ import com.intellij.codeInsight.lookup.impl.LookupImpl;
|
||||
import com.intellij.psi.statistics.StatisticsManager;
|
||||
import com.intellij.psi.statistics.impl.StatisticsManagerImpl;
|
||||
import com.intellij.testFramework.PlatformTestCase;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author mike
|
||||
@@ -95,4 +98,15 @@ public abstract class CompletionTestCase extends DaemonAnalyzerTestCase {
|
||||
protected LookupImpl getActiveLookup() {
|
||||
return (LookupImpl)LookupManager.getActiveLookup(myEditor);
|
||||
}
|
||||
|
||||
protected void assertStringItems(String... strings) {
|
||||
assertNotNull(myItems);
|
||||
List<String> actual = ContainerUtil.map(myItems, new Function<LookupElement, String>() {
|
||||
@Override
|
||||
public String fun(LookupElement element) {
|
||||
return element.getLookupString();
|
||||
}
|
||||
});
|
||||
assertOrderedEquals(actual, strings);
|
||||
}
|
||||
}
|
||||
|
||||
+9
-13
@@ -49,10 +49,10 @@ public class CamelHumpMatcher extends PrefixMatcher {
|
||||
ourLastCompletionCaseSetting = currentSetting;
|
||||
}
|
||||
|
||||
myMatcher = obtainMatcher(myRelaxedMatching);
|
||||
myMatcher = obtainMatcher(myRelaxedMatching, myCaseSensitive);
|
||||
}
|
||||
if (myMatcher.matches(name)) {
|
||||
if (myRelaxedMatching && obtainMatcher(false).matches(name)) {
|
||||
if (myRelaxedMatching && obtainMatcher(false, myCaseSensitive).matches(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -62,11 +62,11 @@ public class CamelHumpMatcher extends PrefixMatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private NameUtil.Matcher obtainMatcher(final boolean relax) {
|
||||
String key = relax + myPrefix;
|
||||
private NameUtil.Matcher obtainMatcher(final boolean relax, final boolean caseSensitive) {
|
||||
String key = relax + myPrefix + caseSensitive;
|
||||
NameUtil.Matcher pattern = ourPatternCache.get(key);
|
||||
if (pattern == null) {
|
||||
pattern = createCamelHumpsMatcher(relax);
|
||||
pattern = createCamelHumpsMatcher(relax, caseSensitive);
|
||||
ourPatternCache.put(key, pattern);
|
||||
}
|
||||
return pattern;
|
||||
@@ -86,12 +86,8 @@ public class CamelHumpMatcher extends PrefixMatcher {
|
||||
if (itemCaseInsensitive && StringUtil.startsWithIgnoreCase(name, myPrefix) || prefixMatches(name)) {
|
||||
return true;
|
||||
}
|
||||
if (itemCaseInsensitive &&
|
||||
CodeInsightSettings.ALL != CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE &&
|
||||
name.length() > 0) {
|
||||
final char c = name.charAt(0);
|
||||
String swappedCase = (Character.isUpperCase(c) ? Character.toLowerCase(c) : Character.toUpperCase(c)) + name.substring(1);
|
||||
if (prefixMatches(swappedCase)) {
|
||||
if (itemCaseInsensitive && CodeInsightSettings.ALL != CodeInsightSettings.getInstance().COMPLETION_CASE_SENSITIVE) {
|
||||
if (obtainMatcher(false, false).matches(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -104,8 +100,8 @@ public class CamelHumpMatcher extends PrefixMatcher {
|
||||
return new CamelHumpMatcher(prefix, myCaseSensitive, myRelaxedMatching);
|
||||
}
|
||||
|
||||
private NameUtil.Matcher createCamelHumpsMatcher(final boolean relaxedMatching) {
|
||||
if (!myCaseSensitive) {
|
||||
private NameUtil.Matcher createCamelHumpsMatcher(final boolean relaxedMatching, final boolean caseSensitive) {
|
||||
if (!caseSensitive) {
|
||||
return NameUtil.buildCompletionMatcher(myPrefix, 0, true, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ public class LookupImpl extends LightweightHint implements Lookup, Disposable {
|
||||
public LookupImpl(Project project, Editor editor, @NotNull LookupArranger arranger){
|
||||
super(new JPanel(new BorderLayout()));
|
||||
setForceShowAsPopup(true);
|
||||
setCancelOnClickOutside(false);
|
||||
myProject = project;
|
||||
myEditor = editor;
|
||||
|
||||
|
||||
@@ -121,7 +121,7 @@ navbar.userActivityMergeTime=500
|
||||
navbar.newpopup=true
|
||||
|
||||
inspectionGadgets.telemetry.enabled=false
|
||||
minuscule.humps.matching=false
|
||||
minuscule.humps.matching=true
|
||||
minuscule.humps.matching.description=Camel Case without holding Shift in Ctrl+N/Ctrl+Shift+N etc
|
||||
|
||||
jvmbugfix.mac.caccessibleLeak=true
|
||||
|
||||
@@ -317,6 +317,10 @@ public class NameUtil {
|
||||
|
||||
private enum WordState { NO_WORD, PREV_UC, WORD }
|
||||
|
||||
private static boolean isWordStart(char p) {
|
||||
return Character.isUpperCase(p) || Character.isDigit(p);
|
||||
}
|
||||
|
||||
private static void addAllWords(String word, List<String> result) {
|
||||
CharacterIterator it = new StringCharacterIterator(word);
|
||||
StringBuffer b = new StringBuffer();
|
||||
@@ -325,7 +329,7 @@ public class NameUtil {
|
||||
for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) {
|
||||
switch (state) {
|
||||
case NO_WORD:
|
||||
if (!Character.isUpperCase(c)) {
|
||||
if (!isWordStart(c)) {
|
||||
b.append(c);
|
||||
state = WordState.WORD;
|
||||
}
|
||||
@@ -335,7 +339,7 @@ public class NameUtil {
|
||||
}
|
||||
break;
|
||||
case PREV_UC:
|
||||
if (!Character.isUpperCase(c)) {
|
||||
if (!isWordStart(c)) {
|
||||
b = startNewWord(result, b, curPrevUC);
|
||||
b.append(c);
|
||||
state = WordState.WORD;
|
||||
@@ -347,7 +351,7 @@ public class NameUtil {
|
||||
}
|
||||
break;
|
||||
case WORD:
|
||||
if (Character.isUpperCase(c)) {
|
||||
if (isWordStart(c)) {
|
||||
startNewWord(result, b, c);
|
||||
b.setLength(0);
|
||||
state = WordState.PREV_UC;
|
||||
@@ -475,14 +479,13 @@ public class NameUtil {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class MinusculeMatcher implements Matcher {
|
||||
private final char[] myPattern;
|
||||
private final boolean myFirstLetterCaseMatters;
|
||||
|
||||
public MinusculeMatcher(String pattern, boolean firstLetterCaseMatters) {
|
||||
myFirstLetterCaseMatters = firstLetterCaseMatters;
|
||||
myPattern = pattern.replaceAll(":", "\\*:").replaceAll("\\.", "\\*\\.").toCharArray();
|
||||
myPattern = StringUtil.trimEnd(pattern, "* ").replaceAll(":", "\\*:").replaceAll("\\.", "\\*\\.").toCharArray();
|
||||
}
|
||||
|
||||
private boolean matches(int patternIndex, List<String> words, int wordIndex) {
|
||||
@@ -501,7 +504,14 @@ public class NameUtil {
|
||||
|
||||
if (isWordSeparator(w.charAt(0))) {
|
||||
assert w.length() == 1 : "'" + w + "'";
|
||||
return matches(isWordSeparator(myPattern[patternIndex]) ? patternIndex + 1 : patternIndex, words, wordIndex + 1);
|
||||
if (isWordSeparator(myPattern[patternIndex])) {
|
||||
return matches(patternIndex + 1, words, wordIndex + 1);
|
||||
}
|
||||
if (patternIndex == 0 && myFirstLetterCaseMatters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return matches(patternIndex, words, wordIndex + 1);
|
||||
}
|
||||
|
||||
if (patternIndex == 0 && myFirstLetterCaseMatters && w.charAt(0) != myPattern[0]) {
|
||||
@@ -512,7 +522,7 @@ public class NameUtil {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean uppers = Character.isUpperCase(myPattern[patternIndex]);
|
||||
boolean uppers = isWordStart(myPattern[patternIndex]);
|
||||
|
||||
int i = 1;
|
||||
while (true) {
|
||||
@@ -523,7 +533,7 @@ public class NameUtil {
|
||||
break;
|
||||
}
|
||||
char p = myPattern[patternIndex + i];
|
||||
if (uppers && Character.isUpperCase(p)) {
|
||||
if (uppers && isWordStart(p)) {
|
||||
p = StringUtil.toLowerCase(p);
|
||||
} else {
|
||||
uppers = false;
|
||||
@@ -570,7 +580,7 @@ public class NameUtil {
|
||||
break;
|
||||
}
|
||||
List<String> newWords = new ArrayList<String>();
|
||||
newWords.add(s.substring(fromIndex));
|
||||
newWords.add(s.substring(next));
|
||||
newWords.addAll(words.subList(i + 1, words.size()));
|
||||
if (matches(patternIndex, newWords, 0)) {
|
||||
return true;
|
||||
@@ -587,7 +597,7 @@ public class NameUtil {
|
||||
|
||||
@Override
|
||||
public boolean matches(String name) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(name, " -_.:", true);
|
||||
StringTokenizer tokenizer = new StringTokenizer(name, " -_.:/", true);
|
||||
List<String> words = new ArrayList<String>();
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String token = tokenizer.nextToken();
|
||||
|
||||
@@ -167,6 +167,7 @@ import.what=Import ''{0}''
|
||||
import.class=Import Class
|
||||
create.class.family.name=Create Class
|
||||
create.class.text=Create Class ''{0}''
|
||||
create.interface.text=Create Interface ''{0}''
|
||||
dynamize.invalid.interface.text=Dynamize invalid interface instantiation
|
||||
dynamize.invalid.interface.family.name=Dynamize invalid code
|
||||
class.to.import.chooser.title=Choose class to import
|
||||
|
||||
+10
-1
@@ -33,6 +33,9 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.plugins.groovy.GroovyBundle;
|
||||
import org.jetbrains.plugins.groovy.actions.GroovyTemplatesFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrInterfaceDefinition;
|
||||
|
||||
/**
|
||||
* @author ilyas
|
||||
@@ -47,7 +50,8 @@ public abstract class CreateClassActionBase implements IntentionAction {
|
||||
|
||||
@NotNull
|
||||
public String getText() {
|
||||
return GroovyBundle.message("create.class.text", myRefElement.getReferenceName());
|
||||
String referenceName = myRefElement.getReferenceName();
|
||||
return shouldCreateInterface() ? GroovyBundle.message("create.interface.text", referenceName) : GroovyBundle.message("create.class.text", referenceName);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -63,6 +67,11 @@ public abstract class CreateClassActionBase implements IntentionAction {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean shouldCreateInterface() {
|
||||
PsiElement parent = myRefElement.getParent();
|
||||
return parent instanceof GrImplementsClause || parent instanceof GrExtendsClause && parent.getParent() instanceof GrInterfaceDefinition;
|
||||
}
|
||||
|
||||
public static PsiClass createClassByType(final PsiDirectory directory,
|
||||
final String name,
|
||||
final PsiManager manager,
|
||||
|
||||
+1
-2
@@ -35,7 +35,6 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrNewExpression;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrImplementsClause;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrMemberOwner;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrMethod;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.expectedTypes.SupertypeConstraint;
|
||||
@@ -111,7 +110,7 @@ public abstract class CreateClassFix {
|
||||
PsiDirectory targetDirectory = getTargetDirectory(project, qualifier, name, module);
|
||||
if (targetDirectory == null) return;
|
||||
|
||||
String templateName = myRefElement.getParent() instanceof GrImplementsClause ? NewGroovyClassAction.GROOVY_INTERFACE : NewGroovyClassAction.GROOVY_CLASS;
|
||||
String templateName = shouldCreateInterface() ? NewGroovyClassAction.GROOVY_INTERFACE : NewGroovyClassAction.GROOVY_CLASS;
|
||||
PsiClass targetClass = createClassByType(targetDirectory, name, manager, myRefElement, templateName);
|
||||
if (targetClass != null) {
|
||||
addImportForClass(groovyFile, qualifier, targetClass);
|
||||
|
||||
@@ -47,7 +47,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinary
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCommandArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterList;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Block implementation for Groovy formatter
|
||||
@@ -61,15 +63,23 @@ public class GroovyBlock implements Block, GroovyElementTypes {
|
||||
final protected Indent myIndent;
|
||||
final protected Wrap myWrap;
|
||||
final protected CodeStyleSettings mySettings;
|
||||
final protected Map<GrBinaryExpression, Alignment> myInnerAlignments;
|
||||
|
||||
|
||||
protected List<Block> mySubBlocks = null;
|
||||
|
||||
public GroovyBlock(@NotNull final ASTNode node, @Nullable final Alignment alignment, @NotNull final Indent indent, @Nullable final Wrap wrap, final CodeStyleSettings settings) {
|
||||
this(node, alignment, indent, wrap, settings, Collections.<GrBinaryExpression, Alignment>emptyMap());
|
||||
}
|
||||
|
||||
public GroovyBlock(@NotNull final ASTNode node, @Nullable final Alignment alignment, @NotNull final Indent indent, @Nullable final Wrap wrap, final CodeStyleSettings settings,
|
||||
@NotNull Map<GrBinaryExpression, Alignment> innerAlignments) {
|
||||
myNode = node;
|
||||
myAlignment = alignment;
|
||||
myIndent = indent;
|
||||
myWrap = wrap;
|
||||
mySettings = settings;
|
||||
myInnerAlignments = innerAlignments;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+94
-38
@@ -27,6 +27,7 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.templateLanguages.OuterLanguageElement;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.containers.CollectionFactory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.plugins.groovy.GroovyFileType;
|
||||
import org.jetbrains.plugins.groovy.formatter.processors.GroovyIndentProcessor;
|
||||
@@ -34,6 +35,8 @@ import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.parser.GroovyElementTypes;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrThrowsClause;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrLabeledStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrCodeBlock;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
|
||||
@@ -42,7 +45,9 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.params.GrParameterLi
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrExtendsClause;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Utility class to generate myBlock hierarchy
|
||||
@@ -66,7 +71,7 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
|
||||
PsiElement blockPsi = block.getNode().getPsi();
|
||||
if (blockPsi instanceof GrBinaryExpression &&
|
||||
!(blockPsi.getParent() instanceof GrBinaryExpression)) {
|
||||
return generateForBinaryExpr(node, myWrap, mySettings);
|
||||
return generateForBinaryExpr(node, myWrap, mySettings, block.myInnerAlignments);
|
||||
}
|
||||
|
||||
//For multiline strings
|
||||
@@ -119,33 +124,93 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
|
||||
// For Parameter lists
|
||||
if (isListLikeClause(blockPsi)) {
|
||||
final ArrayList<Block> subBlocks = new ArrayList<Block>();
|
||||
ASTNode[] children = node.getChildren(null);
|
||||
ASTNode prevChildNode = null;
|
||||
final Alignment alignment = mustAlign(blockPsi, mySettings, children) ? Alignment.createAlignment() : null;
|
||||
final Alignment alignment = mustAlign(blockPsi, mySettings, node.getChildren(null)) ? Alignment.createAlignment() : null;
|
||||
for (ASTNode childNode : visibleChildren(node)) {
|
||||
final Indent indent = GroovyIndentProcessor.getChildIndent(block, prevChildNode, childNode);
|
||||
subBlocks.add(new GroovyBlock(childNode, isKeyword(childNode) ? null : alignment, indent, myWrap, mySettings));
|
||||
prevChildNode = childNode;
|
||||
}
|
||||
return subBlocks;
|
||||
}
|
||||
|
||||
if (blockPsi instanceof GrCodeBlock) {
|
||||
List<ASTNode> children = visibleChildren(node);
|
||||
Map<GrBinaryExpression, Alignment> innerAlignments = calculateInnerAlignments(children);
|
||||
final ArrayList<Block> subBlocks = new ArrayList<Block>();
|
||||
ASTNode prevChildNode = null;
|
||||
for (ASTNode childNode : children) {
|
||||
if (canBeCorrectBlock(childNode)) {
|
||||
final Indent indent = GroovyIndentProcessor.getChildIndent(block, prevChildNode, childNode);
|
||||
subBlocks.add(new GroovyBlock(childNode, isKeyword(childNode) ? null : alignment, indent, myWrap, mySettings));
|
||||
prevChildNode = childNode;
|
||||
}
|
||||
final Indent indent = GroovyIndentProcessor.getChildIndent(block, prevChildNode, childNode);
|
||||
subBlocks.add(new GroovyBlock(childNode, null, indent, myWrap, mySettings, innerAlignments));
|
||||
prevChildNode = childNode;
|
||||
}
|
||||
return subBlocks;
|
||||
}
|
||||
|
||||
// For other cases
|
||||
final ArrayList<Block> subBlocks = new ArrayList<Block>();
|
||||
ASTNode[] children = getGroovyChildren(node);
|
||||
ASTNode prevChildNode = null;
|
||||
for (ASTNode childNode : children) {
|
||||
if (canBeCorrectBlock(childNode)) {
|
||||
final Indent indent = GroovyIndentProcessor.getChildIndent(block, prevChildNode, childNode);
|
||||
subBlocks.add(new GroovyBlock(childNode, blockPsi instanceof GrCodeBlock ? null : myAlignment, indent, myWrap, mySettings));
|
||||
prevChildNode = childNode;
|
||||
}
|
||||
for (ASTNode childNode : visibleChildren(node)) {
|
||||
final Indent indent = GroovyIndentProcessor.getChildIndent(block, prevChildNode, childNode);
|
||||
subBlocks.add(new GroovyBlock(childNode, myAlignment, indent, myWrap, mySettings, block.myInnerAlignments));
|
||||
prevChildNode = childNode;
|
||||
}
|
||||
return subBlocks;
|
||||
}
|
||||
|
||||
private static Map<GrBinaryExpression, Alignment> calculateInnerAlignments(List<ASTNode> children) {
|
||||
Map<GrBinaryExpression, Alignment> innerAlignments = CollectionFactory.hashMap();
|
||||
List<Alignment> currentGroup = null;
|
||||
for (ASTNode child : children) {
|
||||
PsiElement psi = child.getPsi();
|
||||
if (psi instanceof GrLabeledStatement) {
|
||||
List<GrBinaryExpression> table = getTable(((GrLabeledStatement)psi).getStatement());
|
||||
if (table.isEmpty()) {
|
||||
currentGroup = null;
|
||||
}
|
||||
else {
|
||||
currentGroup = new ArrayList<Alignment>();
|
||||
for (GrBinaryExpression expression : table) {
|
||||
Alignment alignment = Alignment.createAlignment(true);
|
||||
currentGroup.add(alignment);
|
||||
innerAlignments.put(expression, alignment);
|
||||
}
|
||||
}
|
||||
} else if (currentGroup != null && isTablePart(psi)) {
|
||||
List<GrBinaryExpression> table = getTable((GrStatement)psi);
|
||||
for (int i = 0; i < Math.min(table.size(), currentGroup.size()); i++) {
|
||||
innerAlignments.put(table.get(i), currentGroup.get(i));
|
||||
}
|
||||
} else {
|
||||
currentGroup = null;
|
||||
}
|
||||
}
|
||||
return innerAlignments;
|
||||
}
|
||||
|
||||
private static List<GrBinaryExpression> getTable(GrStatement statement) {
|
||||
LinkedList<GrBinaryExpression> result = new LinkedList<GrBinaryExpression>();
|
||||
while (isTablePart(statement)) {
|
||||
result.addFirst((GrBinaryExpression)statement);
|
||||
statement = ((GrBinaryExpression)statement).getLeftOperand();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isTablePart(PsiElement psi) {
|
||||
return psi instanceof GrBinaryExpression && mBOR == ((GrBinaryExpression)psi).getOperationTokenType();
|
||||
}
|
||||
|
||||
private static List<ASTNode> visibleChildren(ASTNode node) {
|
||||
ArrayList<ASTNode> list = new ArrayList<ASTNode>();
|
||||
for (ASTNode astNode : getGroovyChildren(node)) {
|
||||
if (canBeCorrectBlock(astNode)) {
|
||||
list.add(astNode);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
private static boolean mustAlign(PsiElement blockPsi, CodeStyleSettings mySettings, ASTNode[] children) {
|
||||
// We don't want to align single call argument if it's a closure. The reason is that it looks better to have call like
|
||||
//
|
||||
@@ -276,23 +341,14 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
|
||||
* @return
|
||||
* @param node
|
||||
*/
|
||||
private static List<Block> generateForBinaryExpr(final ASTNode node, Wrap myWrap, CodeStyleSettings mySettings) {
|
||||
private static List<Block> generateForBinaryExpr(final ASTNode node, Wrap myWrap, CodeStyleSettings mySettings, Map<GrBinaryExpression, Alignment> inner) {
|
||||
final ArrayList<Block> subBlocks = new ArrayList<Block>();
|
||||
Alignment alignment = mySettings.ALIGN_MULTILINE_BINARY_OPERATION ? Alignment.createAlignment() : null;
|
||||
GrBinaryExpression myExpr = (GrBinaryExpression) node.getPsi();
|
||||
ASTNode[] children = node.getChildren(null);
|
||||
if (myExpr.getLeftOperand() instanceof GrBinaryExpression) {
|
||||
addBinaryChildrenRecursively(myExpr.getLeftOperand(), subBlocks, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings);
|
||||
}
|
||||
for (ASTNode childNode : children) {
|
||||
if (canBeCorrectBlock(childNode) &&
|
||||
!(childNode.getPsi() instanceof GrBinaryExpression)) {
|
||||
subBlocks.add(new GroovyBlock(childNode, alignment, Indent.getContinuationWithoutFirstIndent(), myWrap, mySettings));
|
||||
}
|
||||
}
|
||||
if (myExpr.getRightOperand() instanceof GrBinaryExpression) {
|
||||
addBinaryChildrenRecursively(myExpr.getRightOperand(), subBlocks, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings);
|
||||
}
|
||||
|
||||
|
||||
GrBinaryExpression binary = (GrBinaryExpression) node.getPsi();
|
||||
assert binary != null;
|
||||
addBinaryChildrenRecursively(binary, subBlocks, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings, inner);
|
||||
return subBlocks;
|
||||
}
|
||||
|
||||
@@ -307,23 +363,23 @@ public class GroovyBlockGenerator implements GroovyElementTypes {
|
||||
private static void addBinaryChildrenRecursively(PsiElement elem,
|
||||
List<Block> list,
|
||||
Indent indent,
|
||||
Alignment alignment, Wrap myWrap, CodeStyleSettings mySettings) {
|
||||
Alignment alignment, Wrap myWrap, CodeStyleSettings mySettings, Map<GrBinaryExpression, Alignment> inner) {
|
||||
if (elem == null) return;
|
||||
ASTNode[] children = elem.getNode().getChildren(null);
|
||||
// For binary expressions
|
||||
if ((elem instanceof GrBinaryExpression)) {
|
||||
GrBinaryExpression myExpr = ((GrBinaryExpression) elem);
|
||||
if (myExpr.getLeftOperand() instanceof GrBinaryExpression) {
|
||||
addBinaryChildrenRecursively(myExpr.getLeftOperand(), list, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings);
|
||||
addBinaryChildrenRecursively(myExpr.getLeftOperand(), list, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings, inner);
|
||||
}
|
||||
for (ASTNode childNode : children) {
|
||||
if (canBeCorrectBlock(childNode) &&
|
||||
!(childNode.getPsi() instanceof GrBinaryExpression)) {
|
||||
list.add(new GroovyBlock(childNode, alignment, indent, myWrap, mySettings));
|
||||
PsiElement op = ((GrBinaryExpression)elem).getOperationToken();
|
||||
for (ASTNode childNode : visibleChildren(elem.getNode())) {
|
||||
PsiElement psi = childNode.getPsi();
|
||||
if (!(psi instanceof GrBinaryExpression)) {
|
||||
list.add(new GroovyBlock(childNode, op == psi ? inner.get(myExpr) : alignment, indent, myWrap, mySettings));
|
||||
}
|
||||
}
|
||||
if (myExpr.getRightOperand() instanceof GrBinaryExpression) {
|
||||
addBinaryChildrenRecursively(myExpr.getRightOperand(), list, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings);
|
||||
addBinaryChildrenRecursively(myExpr.getRightOperand(), list, Indent.getContinuationWithoutFirstIndent(), alignment, myWrap, mySettings, inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,8 @@ public class FormatterTest extends GroovyFormatterTestCase {
|
||||
public void testClosureAfterLineComment() throws Throwable { doTest(); }
|
||||
public void testAnnotationOnSeparateLine() throws Throwable { doTest(); }
|
||||
|
||||
public void testSpockTable() throws Throwable { doTest(); }
|
||||
|
||||
public void testElseIfs() throws Throwable {
|
||||
myTempSettings.SPECIAL_ELSE_IF_TREATMENT = false;
|
||||
doTest();
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
class HelloSpock extends spock.lang.Specification {
|
||||
def "length of Spock's and his friends' names"() {
|
||||
expect:
|
||||
name.size() == length
|
||||
|
||||
where:
|
||||
name | length | foo
|
||||
"Spock" | 5
|
||||
"Kirk" | 4 | xxx | yyy
|
||||
"Scotty" | 6 |dddddddddd | fff
|
||||
|
||||
//aaa
|
||||
a | b | c
|
||||
}
|
||||
}
|
||||
-----
|
||||
class HelloSpock extends spock.lang.Specification {
|
||||
def "length of Spock's and his friends' names"() {
|
||||
expect:
|
||||
name.size() == length
|
||||
|
||||
where:
|
||||
name | length | foo
|
||||
"Spock" | 5
|
||||
"Kirk" | 4 | xxx | yyy
|
||||
"Scotty" | 6 | dddddddddd | fff
|
||||
|
||||
//aaa
|
||||
a | b | c
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user