Merge remote-tracking branch 'origin/master'

This commit is contained in:
Alexander Lobas
2012-05-18 14:58:42 +04:00
41 changed files with 677 additions and 388 deletions
@@ -17,7 +17,7 @@ package com.intellij.ide.macro;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.psi.JavaDirectoryService;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiFile;
@@ -41,7 +41,7 @@ public final class FilePackageMacro extends Macro {
@Nullable
static PsiPackage getFilePackage(DataContext dataContext) {
PsiFile psiFile = DataKeys.PSI_FILE.getData(dataContext);
PsiFile psiFile = LangDataKeys.PSI_FILE.getData(dataContext);
if (psiFile == null) return null;
PsiDirectory containingDirectory = psiFile.getContainingDirectory();
if (containingDirectory == null || !containingDirectory.isValid()) return null;
@@ -33,6 +33,7 @@ public class LineRange {
public LineRange(final int startLine, final int endLine) {
this.startLine = startLine;
this.endLine = endLine;
LOG.assertTrue(startLine > 0, "Negative start line");
if (startLine > endLine) {
LOG.error("start > end: start=" + startLine+"; end="+endLine);
}
@@ -18,8 +18,6 @@ package com.intellij.ide.macro;
import com.intellij.application.options.PathMacrosImpl;
import com.intellij.ide.DataManager;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.impl.DataManagerImpl;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.components.ServiceManager;
@@ -147,11 +145,11 @@ public final class MacroManager {
String name = "$" + macro.getName() + "$";
if (str.indexOf(name) >= 0) {
String expanded = macro.expand(dataContext);
if (dataContext instanceof DataManagerImpl.MyDataContext) {
// hack: macro.expand() can cause UI events such as showing dialogs ('Prompt' macro) which may 'invalidate' the datacontext
// since we know exactly that context is valid, we need to update its event count
((DataManagerImpl.MyDataContext)dataContext).setEventCount(IdeEventQueue.getInstance().getEventCount());
}
//if (dataContext instanceof DataManagerImpl.MyDataContext) {
// // hack: macro.expand() can cause UI events such as showing dialogs ('Prompt' macro) which may 'invalidate' the datacontext
// // since we know exactly that context is valid, we need to update its event count
// ((DataManagerImpl.MyDataContext)dataContext).setEventCount(IdeEventQueue.getInstance().getEventCount());
//}
if (expanded == null) {
expanded = "";
}
@@ -0,0 +1,59 @@
/*
* Copyright 2000-2012 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 com.intellij.tools;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.DataKey;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import org.jetbrains.annotations.NonNls;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author Konstantin Bulenkov
*/
class HackyDataContext implements DataContext {
private static DataKey[] keys = {
PlatformDataKeys.PROJECT,
PlatformDataKeys.PROJECT_FILE_DIRECTORY,
PlatformDataKeys.EDITOR,
PlatformDataKeys.VIRTUAL_FILE,
LangDataKeys.MODULE,
LangDataKeys.PSI_FILE
};
private final Map<String, Object> values = new HashMap<String, Object>();
public HackyDataContext(DataContext context) {
for (DataKey key : keys) {
values.put(key.getName(), key.getData(context));
}
}
@Override
public Object getData(@NonNls String dataId) {
if (values.keySet().contains(dataId)) {
return values.get(dataId);
}
//noinspection UseOfSystemOutOrSystemErr
System.out.println("Please add " + dataId + " key in " + getClass().getName());
return null;
}
}
@@ -35,10 +35,11 @@ public class ToolAction extends AnAction implements DumbAware {
public void actionPerformed(AnActionEvent e) {
MacroManager.getInstance().cacheMacrosPreview(e.getDataContext());
final HackyDataContext dataContext = new HackyDataContext(e.getDataContext());
Tool[] tools = ToolManager.getInstance().getTools();
for (Tool tool : tools) {
if (myActionId.equals(tool.getActionId())) {
tool.execute(e.getDataContext());
tool.execute(dataContext);
break;
}
}
@@ -28,8 +28,6 @@ import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessTerminatedListener;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.impl.DataManagerImpl;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
@@ -48,11 +46,11 @@ public class ToolRunProfile implements ModuleRunProfile{
public ToolRunProfile(final Tool tool, final DataContext context) {
myTool = tool;
myCommandLine = myTool.createCommandLine(context);
if (context instanceof DataManagerImpl.MyDataContext) {
// hack: macro.expand() can cause UI events such as showing dialogs ('Prompt' macro) which may 'invalidate' the datacontext
// since we know exactly that context is valid, we need to update its event count
((DataManagerImpl.MyDataContext)context).setEventCount(IdeEventQueue.getInstance().getEventCount());
}
//if (context instanceof DataManagerImpl.MyDataContext) {
// // hack: macro.expand() can cause UI events such as showing dialogs ('Prompt' macro) which may 'invalidate' the datacontext
// // since we know exactly that context is valid, we need to update its event count
// ((DataManagerImpl.MyDataContext)context).setEventCount(IdeEventQueue.getInstance().getEventCount());
//}
}
public String getName() {
@@ -308,7 +308,7 @@ public class DataManagerImpl extends DataManager implements ApplicationComponent
PlatformDataKeys.MODALITY_STATE.getName()
));
public class MyDataContext implements DataContext, UserDataHolder {
public static class MyDataContext implements DataContext, UserDataHolder {
private int myEventCount;
// To prevent memory leak we have to wrap passed component into
// the weak reference. For example, Swing often remembers menu items
@@ -322,7 +322,9 @@ public class DataManagerImpl extends DataManager implements ApplicationComponent
myRef = new WeakReference<Component>(component);
}
public void setEventCount(int eventCount) {
public void setEventCount(int eventCount, Object caller) {
assert caller instanceof IdeKeyEventDispatcher : "This method might be accessible from " + IdeKeyEventDispatcher.class.getName() + " only";
myCachedData.clear();
myEventCount = eventCount;
}
@@ -366,11 +368,11 @@ public class DataManagerImpl extends DataManager implements ApplicationComponent
return _component != null ? ModalityState.stateForComponent(_component) : ModalityState.NON_MODAL;
}
else if (PlatformDataKeys.EDITOR.is(dataId)) {
Editor editor = (Editor)DataManagerImpl.this.getData(dataId, _component);
Editor editor = (Editor)(((DataManagerImpl)DataManager.getInstance()).getData(dataId, _component));
return validateEditor(editor);
}
else {
return DataManagerImpl.this.getData(dataId, _component);
return (((DataManagerImpl)DataManager.getInstance()).getData(dataId, _component));
}
}
@@ -580,7 +580,7 @@ public final class IdeKeyEventDispatcher implements Disposable {
processor.onUpdatePassed(e, action, actionEvent);
((DataManagerImpl.MyDataContext)myContext.getDataContext()).setEventCount(IdeEventQueue.getInstance().getEventCount());
((DataManagerImpl.MyDataContext)myContext.getDataContext()).setEventCount(IdeEventQueue.getInstance().getEventCount(), this);
actionManager.fireBeforeActionPerformed(action, actionEvent.getDataContext(), actionEvent);
Component component = PlatformDataKeys.CONTEXT_COMPONENT.getData(actionEvent.getDataContext());
if (component != null && !component.isShowing()) {
@@ -16,8 +16,6 @@
package com.intellij.lang.ant.config.actions;
import com.intellij.ide.IdeEventQueue;
import com.intellij.ide.impl.DataManagerImpl;
import com.intellij.lang.ant.config.AntBuildFile;
import com.intellij.lang.ant.config.AntConfiguration;
import com.intellij.lang.ant.config.AntConfigurationListener;
@@ -25,7 +23,6 @@ import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
@@ -83,12 +80,12 @@ public class TargetActionStub extends AnAction implements Disposable {
return;
}
if (!myActionInvoked.getAndSet(true)) {
final DataContext context = e.getDataContext();
if (context instanceof DataManagerImpl.MyDataContext) {
// hack: macro.expand() can cause UI events such as showing dialogs ('Prompt' macro) which may 'invalidate' the datacontext
// since we know exactly that context is valid, we need to update its event count
((DataManagerImpl.MyDataContext)context).setEventCount(IdeEventQueue.getInstance().getEventCount());
}
//final DataContext context = e.getDataContext();
//if (context instanceof DataManagerImpl.MyDataContext) {
// // hack: macro.expand() can cause UI events such as showing dialogs ('Prompt' macro) which may 'invalidate' the datacontext
// // since we know exactly that context is valid, we need to update its event count
// ((DataManagerImpl.MyDataContext)context).setEventCount(IdeEventQueue.getInstance().getEventCount());
//}
action.actionPerformed(e);
}
}
@@ -61,7 +61,8 @@ public class GDKSuperMethodSearcher implements QueryExecutor<MethodSignatureBack
final String name = method.getName();
final MethodResolverProcessor processor = new MethodResolverProcessor(name, ((GrMethod)method), false, null, null, PsiType.EMPTY_ARRAY);
ResolveUtil.processNonCodeMembers(JavaPsiFacade.getElementFactory(project).createType(psiClass), processor, (GrMethod)method);
ResolveUtil.processNonCodeMembers(JavaPsiFacade.getElementFactory(project).createType(psiClass), processor, (GrMethod)method,
ResolveState.initial());
final GroovyResolveResult[] candidates = processor.getCandidates();
@@ -144,7 +144,7 @@ public class LiteralConstructorReference extends PsiReferenceBase.Poly<GrListOrM
final GroovyResolveResult[] constructorCandidates =
PsiUtil.getConstructorCandidates(myExpectedType, getCallArgumentTypes(), getElement());
if (constructorCandidates.length == 0) {
if (constructorCandidates.length == 0 && classResolveResult.getElement() != null) {
return new GroovyResolveResult[]{new GroovyResolveResultImpl(classResolveResult)};
}
return constructorCandidates;
@@ -15,9 +15,10 @@
*/
package org.jetbrains.plugins.groovy.lang.psi.api;
import com.intellij.psi.ResolveResult;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiSubstitutor;
import com.intellij.psi.ResolveResult;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
@@ -34,10 +35,14 @@ public interface GroovyResolveResult extends ResolveResult {
@Nullable
GroovyPsiElement getCurrentFileResolveContext();
@NotNull
PsiSubstitutor getSubstitutor();
boolean isInvokedOnProperty();
@Nullable
SpreadState getSpreadState();
GroovyResolveResult EMPTY_RESULT = new GroovyResolveResult() {
public boolean isAccessible() {
return false;
@@ -51,6 +56,7 @@ public interface GroovyResolveResult extends ResolveResult {
return true;
}
@NotNull
public PsiSubstitutor getSubstitutor() {
return PsiSubstitutor.EMPTY;
}
@@ -68,5 +74,10 @@ public interface GroovyResolveResult extends ResolveResult {
public boolean isInvokedOnProperty() {
return false;
}
@Override
public SpreadState getSpreadState() {
return null;
}
};
}
@@ -0,0 +1,55 @@
/*
* Copyright 2000-2012 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.lang.psi.api;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Key;
import com.intellij.psi.PsiType;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
/**
* @author Max Medvedev
*/
public final class SpreadState {
public static final Key<SpreadState> SPREAD_STATE = Key.create("Spread state");
private final PsiType containerType;
@Nullable private final SpreadState innerState;
public SpreadState(PsiType type, @Nullable SpreadState state) {
containerType = type;
innerState = state;
}
public PsiType getContainerType() {
return containerType;
}
@Nullable
public SpreadState getInnerState() {
return innerState;
}
public static SpreadState create(PsiType type, @Nullable SpreadState state) {
return new SpreadState(type, state);
}
public static PsiType apply(PsiType item, @Nullable SpreadState state, Project project) {
if (state == null) return item;
return apply(TypesUtil.createSimilarCollection(state.getContainerType(), project, item), state.getInnerState(), project);
}
}
@@ -0,0 +1,78 @@
/*
* Copyright 2000-2012 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.lang.psi.impl;
import com.intellij.openapi.project.Project;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiType;
import com.intellij.psi.search.GlobalSearchScope;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
/**
* @author Max Medvedev
*/
public class GrSpreadType extends GrLiteralClassType {
private PsiType myType;
public GrSpreadType(PsiType original, PsiType containerType, GlobalSearchScope scope) {
this(original, containerType, LanguageLevel.JDK_1_5, scope, JavaPsiFacade.getInstance(scope.getProject()));
}
public GrSpreadType(PsiType original, PsiType containerType, LanguageLevel languageLevel, GlobalSearchScope scope, JavaPsiFacade facade) {
super(languageLevel, scope, facade);
final Project project = facade.getProject();
myType = TypesUtil.createSimilarCollection(containerType, project, original);
}
@NotNull
@Override
protected String getJavaClassName() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@NotNull
@Override
public String getClassName() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@NotNull
@Override
public PsiType[] getParameters() {
return new PsiType[0]; //To change body of implemented methods use File | Settings | File Templates.
}
@NotNull
@Override
public PsiClassType setLanguageLevel(@NotNull LanguageLevel languageLevel) {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public String getInternalCanonicalText() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
public boolean isValid() {
return false; //To change body of implemented methods use File | Settings | File Templates.
}
}
@@ -16,10 +16,12 @@
package org.jetbrains.plugins.groovy.lang.psi.impl;
import com.intellij.psi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GrClassSubstitutor;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
/**
* @author ven
@@ -31,28 +33,30 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
private final PsiSubstitutor mySubstitutor;
private final boolean myIsInvokedOnProperty;
private GroovyPsiElement myCurrentFileResolveContext;
private final GroovyPsiElement myCurrentFileResolveContext;
private final SpreadState mySpreadState;
public GroovyResolveResultImpl(PsiElement element, boolean isAccessible) {
this(element, null, PsiSubstitutor.EMPTY, isAccessible, true);
public GroovyResolveResultImpl(@NotNull PsiElement element, boolean isAccessible) {
this(element, null, null, PsiSubstitutor.EMPTY, isAccessible, true, false);
}
public GroovyResolveResultImpl(PsiElement element,
@Nullable GroovyPsiElement context,
PsiSubstitutor substitutor,
public GroovyResolveResultImpl(@NotNull PsiElement element,
@Nullable GroovyPsiElement resolveContext,
@Nullable SpreadState spreadState,
@NotNull PsiSubstitutor substitutor,
boolean isAccessible,
boolean staticsOK) {
this(element, context, substitutor, isAccessible, staticsOK, false);
this(element, resolveContext, spreadState, substitutor, isAccessible, staticsOK, false);
}
public GroovyResolveResultImpl(PsiClassType.ClassResolveResult classResolveResult) {
this(classResolveResult.getElement(), null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(),
classResolveResult.isStaticsScopeCorrect());
this(classResolveResult.getElement(), null, null, classResolveResult.getSubstitutor(), classResolveResult.isAccessible(), classResolveResult.isStaticsScopeCorrect(), false);
}
public GroovyResolveResultImpl(PsiElement element,
GroovyPsiElement resolveContext,
PsiSubstitutor substitutor,
public GroovyResolveResultImpl(@NotNull PsiElement element,
@Nullable GroovyPsiElement resolveContext,
@Nullable SpreadState spreadState,
@NotNull PsiSubstitutor substitutor,
boolean isAccessible,
boolean staticsOK,
boolean isInvokedOnProperty) {
@@ -62,8 +66,10 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
mySubstitutor = substitutor;
myIsStaticsOK = staticsOK;
myIsInvokedOnProperty = isInvokedOnProperty;
mySpreadState = spreadState;
}
@NotNull
public PsiSubstitutor getSubstitutor() {
return mySubstitutor;
}
@@ -108,6 +114,7 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
return result;
}
@Nullable
public GroovyPsiElement getCurrentFileResolveContext() {
return myCurrentFileResolveContext;
}
@@ -116,6 +123,11 @@ public class GroovyResolveResultImpl implements GroovyResolveResult {
return myIsInvokedOnProperty;
}
@Override
public SpreadState getSpreadState() {
return mySpreadState;
}
@Override
public String toString() {
return "GroovyResolveResultImpl{" +
@@ -95,7 +95,7 @@ public class GrConstructorInvocationImpl extends GrCallImpl implements GrConstru
}
public GroovyResolveResult[] multiResolveClass() {
return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, PsiSubstitutor.EMPTY, true, true)};
return new GroovyResolveResult[]{new GroovyResolveResultImpl(getDelegatedClass(), this, null, PsiSubstitutor.EMPTY, true, true)};
}
public PsiMethod resolveMethod() {
@@ -35,6 +35,7 @@ import org.jetbrains.plugins.groovy.lang.completion.GroovyCompletionUtil;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
@@ -117,7 +118,7 @@ public class CompleteReferenceExpression {
getVariantsFromQualifierForSpreadOperator(refExpr, processor, qualifier);
}
}
ResolveUtil.processCategoryMembers(refExpr, processor);
ResolveUtil.processCategoryMembers(refExpr, processor, ResolveState.initial());
}
private static void getVariantsFromQualifierForSpreadOperator(GrReferenceExpression refExpr,
@@ -206,8 +207,8 @@ public class CompleteReferenceExpression {
final GrPropertyForCompletion field = new GrPropertyForCompletion(method, name, type);
if (resolveResult != null) {
return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSubstitutor(),
resolveResult.isAccessible(), resolveResult.isStaticsOK());
return new GroovyResolveResultImpl(field, resolveResult.getCurrentFileResolveContext(), resolveResult.getSpreadState(),
resolveResult.getSubstitutor(), resolveResult.isAccessible(), resolveResult.isStaticsOK(), false);
}
else {
return new GroovyResolveResultImpl(field, true);
@@ -377,12 +378,13 @@ public class CompleteReferenceExpression {
boolean isAccessible = isAccessible(namedElement);
final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
boolean isStaticsOK = isStaticsOK(namedElement, resolveContext, myParameters.getInvocationCount() <= 1);
PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
consume(new GroovyResolveResultImpl(namedElement, resolveContext, substitutor, isAccessible, isStaticsOK));
consume(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
return true;
}
@@ -407,7 +409,7 @@ public class CompleteReferenceExpression {
element = ((GrReflectedMethod)element).getBaseMethod();
if (!myProcessedMethodWithOptionalParams.add((GrMethod)element)) return;
result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(),
result = new GroovyResolveResultImpl(element, result.getCurrentFileResolveContext(), result.getSpreadState(),
result.getSubstitutor(), result.isAccessible(), result.isStaticsOK(),
result.isInvokedOnProperty());
}
@@ -42,6 +42,7 @@ import org.jetbrains.plugins.groovy.lang.psi.GroovyElementVisitor;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock;
@@ -64,7 +65,8 @@ import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.*;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mAT;
import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mMEMBER_POINTER;
/**
* @author ilyas
@@ -121,7 +123,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
if (!InheritanceUtil.isInheritor(containingClass, CommonClassNames.JAVA_UTIL_MAP)) continue;
final String name = containingClass.getQualifiedName();
if (name != null && name.startsWith("java.")) continue;
if (containingClass.getLanguage() != GroovyFileType.GROOVY_LANGUAGE && !InheritanceUtil.isInheritor(containingClass, GroovyCommonClassNames.DEFAULT_BASE_CLASS_NAME)) {
if (containingClass.getLanguage() != GroovyFileType.GROOVY_LANGUAGE &&
!InheritanceUtil.isInheritor(containingClass, GroovyCommonClassNames.DEFAULT_BASE_CLASS_NAME)) {
continue;
}
}
@@ -174,7 +177,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
String[] accessorNames = isLValue ? GroovyPropertyUtils.suggestSettersName(name) : GroovyPropertyUtils.suggestGettersName(name);
List<GroovyResolveResult> accessorResults = new ArrayList<GroovyResolveResult>();
for (String accessorName : accessorNames) {
AccessorResolverProcessor accessorResolver = new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments());
AccessorResolverProcessor accessorResolver =
new AccessorResolverProcessor(accessorName, name, this, !isLValue, false, getThisType(), getTypeArguments());
GrReferenceResolveUtil.resolveImpl(accessorResolver, this);
final GroovyResolveResult[] candidates = accessorResolver.getCandidates();
@@ -198,7 +202,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
public GroovyResolveResult[] getCallVariants(GrExpression upToArgument) {
return resolveMethodOrProperty(true, upToArgument, true);
}
@@ -221,13 +224,12 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
}
}
}
}
/**
* priority: inside class C: local variable, c.method, c.property, c.getter
* in other places: local variable, c.method, c.getter, c.property
* in other places: local variable, c.method, c.getter, c.property
*/
private GroovyResolveResult[] resolveMethodOrProperty(boolean allVariants, @Nullable GrExpression upToArgument, boolean genericsMatter) {
final String name = getReferenceName();
@@ -260,7 +262,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
for (GroovyResolveResult result : shapeResults.second) {
final ResolveState state = ResolveState.initial().
put(PsiSubstitutor.KEY, result.getSubstitutor()).
put(ResolverProcessor.RESOLVE_CONTEXT, result.getCurrentFileResolveContext());
put(ResolverProcessor.RESOLVE_CONTEXT, result.getCurrentFileResolveContext()).
put(SpreadState.SPREAD_STATE, result.getSpreadState());
methodResolver.execute(result.getElement(), state);
}
@@ -286,7 +289,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
//search for getters
for (String getterName : GroovyPropertyUtils.suggestGettersName(name)) {
AccessorResolverProcessor getterResolver = new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, getThisType(), getTypeArguments());
AccessorResolverProcessor getterResolver =
new AccessorResolverProcessor(getterName, name, this, true, genericsMatter, getThisType(), getTypeArguments());
GrReferenceResolveUtil.resolveImpl(getterResolver, this);
final GroovyResolveResult[] candidates = getterResolver.getCandidates(); //can be only one candidate
if (!allVariants && candidates.length == 1) {
@@ -308,12 +312,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
assert upToArgument == null;
return CachedValuesManager.getManager(getProject()).getCachedValue(this, new CachedValueProvider<Pair<Boolean, GroovyResolveResult[]>>() {
@Override
public Result<Pair<Boolean, GroovyResolveResult[]>> compute() {
return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT);
}
});
return CachedValuesManager.getManager(getProject())
.getCachedValue(this, new CachedValueProvider<Pair<Boolean, GroovyResolveResult[]>>() {
@Override
public Result<Pair<Boolean, GroovyResolveResult[]>> compute() {
return Result.create(doResolveByShape(false, null), PsiModificationTracker.MODIFICATION_COUNT);
}
});
}
private Pair<Boolean, GroovyResolveResult[]> doResolveByShape(boolean allVariants, @Nullable GrExpression upToArgument) {
@@ -329,7 +334,10 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return Pair.create(shapeProcessor.hasApplicableCandidates(), candidates);
}
private MethodResolverProcessor createMethodProcessor(boolean allVariants, String name, final boolean byShape, @Nullable GrExpression upToArgument) {
private MethodResolverProcessor createMethodProcessor(boolean allVariants,
String name,
final boolean byShape,
@Nullable GrExpression upToArgument) {
final PsiType[] argTypes = PsiUtil.getArgumentTypes(this, false, upToArgument);
if (byShape && argTypes != null) {
for (int i = 0; i < argTypes.length; i++) {
@@ -436,12 +444,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return CachedValuesManager.getManager(getProject()).getCachedValue(this, new CachedValueProvider<GroovyResolveResult[]>() {
@Override
public Result<GroovyResolveResult[]> compute() {
GroovyResolveResult[] value = RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable<GroovyResolveResult[]>() {
@Override
public GroovyResolveResult[] compute() {
return doPolyResolve(false, false);
}
});
GroovyResolveResult[] value =
RecursionManager.doPreventingRecursion(GrReferenceExpressionImpl.this, true, new Computable<GroovyResolveResult[]>() {
@Override
public GroovyResolveResult[] compute() {
return doPolyResolve(false, false);
}
});
if (value == null) {
value = GroovyResolveResult.EMPTY_ARRAY;
}
@@ -459,8 +468,6 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
private static final OurTypesCalculator TYPES_CALCULATOR = new OurTypesCalculator();
public PsiType getNominalType() {
IElementType dotType = getDotTokenType();
final GroovyResolveResult resolveResult = advancedResolve();
PsiElement resolved = resolveResult.getElement();
@@ -471,71 +478,93 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
}
IElementType dotType = getDotTokenType();
if (dotType == mMEMBER_POINTER) {
return GrClosureType.create(multiResolve(false), this);
}
PsiType result = null;
JavaPsiFacade facade = JavaPsiFacade.getInstance(getProject());
if (resolved == null && !"class".equals(getReferenceName())) {
resolved = getReference().resolve();
}
if (resolved instanceof PsiClass) {
if (getParent() instanceof GrReferenceExpression) {
result = facade.getElementFactory().createType((PsiClass) resolved);
} else {
result = TypesUtil
.createJavaLangClassType(facade.getElementFactory().createType((PsiClass)resolved), getProject(), getResolveScope());
}
} else if (resolved instanceof GrVariable) {
result = ((GrVariable) resolved).getDeclaredType();
} else if (resolved instanceof PsiVariable) {
result = ((PsiVariable) resolved).getType();
} else
if (resolved instanceof PsiMethod) {
PsiMethod method = (PsiMethod) resolved;
if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) {
result = method.getParameterList().getParameters()[0].getType();
} else {
PsiClass containingClass = method.getContainingClass();
if (containingClass != null && CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
"getClass".equals(method.getName())) {
result = TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
} else {
result = PsiUtil.getSmartReturnType(method);
}
PsiType result = getNominalTypeInner(resolved);
if (result == null) return null;
result = TypesUtil.substituteBoxAndNormalizeType(result, resolveResult.getSubstitutor(), resolveResult.getSpreadState(), this);
return result;
}
@Nullable
private PsiType getNominalTypeInner(PsiElement resolved) {
if (resolved == null && !"class".equals(getReferenceName())) {
resolved = resolve();
}
if (resolved instanceof PsiClass) {
final PsiElementFactory factory = JavaPsiFacade.getInstance(getProject()).getElementFactory();
if (getParent() instanceof GrReferenceExpression) {
return factory.createType((PsiClass)resolved);
}
} else if (resolved instanceof GrReferenceExpression) {
else {
return TypesUtil.createJavaLangClassType(factory.createType((PsiClass)resolved), getProject(), getResolveScope());
}
}
if (resolved instanceof GrVariable) {
return ((GrVariable)resolved).getDeclaredType();
}
if (resolved instanceof PsiVariable) {
return ((PsiVariable)resolved).getType();
}
if (resolved instanceof PsiMethod) {
PsiMethod method = (PsiMethod)resolved;
if (PropertyUtil.isSimplePropertySetter(method) && !method.getName().equals(getReferenceName())) {
return method.getParameterList().getParameters()[0].getType();
}
//'class' property with explicit generic
PsiClass containingClass = method.getContainingClass();
if (containingClass != null &&
CommonClassNames.JAVA_LANG_OBJECT.equals(containingClass.getQualifiedName()) &&
"getClass".equals(method.getName())) {
return TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
}
return PsiUtil.getSmartReturnType(method);
}
if (resolved instanceof GrReferenceExpression) {
PsiElement parent = resolved.getParent();
if (parent instanceof GrAssignmentExpression) {
GrAssignmentExpression assignment = (GrAssignmentExpression) parent;
GrAssignmentExpression assignment = (GrAssignmentExpression)parent;
if (resolved.equals(assignment.getLValue())) {
GrExpression rValue = assignment.getRValue();
if (rValue != null) {
PsiType rType = rValue.getType();
if (rType != null) result = rType;
if (rType != null) {
return rType;
}
}
}
}
}
else if (resolved == null) {
GrExpression qualifier = getQualifierExpression();
if (resolved == null) {
if ("class".equals(getReferenceName())) {
result = TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
return TypesUtil.createJavaLangClassType(getQualifierType(), getProject(), getResolveScope());
}
else {
if (qualifier != null) {
PsiType qType = qualifier.getType();
if (qType instanceof PsiClassType) {
PsiClassType.ClassResolveResult qResult = ((PsiClassType)qType).resolveGenerics();
PsiClass clazz = qResult.getElement();
if (clazz != null) {
PsiClass mapClass = facade.findClass(CommonClassNames.JAVA_UTIL_MAP, getResolveScope());
if (mapClass != null && mapClass.getTypeParameters().length == 2) {
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
if (substitutor != null) {
result = TypeConversionUtil.erasure(substitutor.substitute(mapClass.getTypeParameters()[1]));
}
//map access
GrExpression qualifier = getQualifierExpression();
if (qualifier != null) {
PsiType qType = qualifier.getType();
if (qType instanceof PsiClassType) {
PsiClassType.ClassResolveResult qResult = ((PsiClassType)qType).resolveGenerics();
PsiClass clazz = qResult.getElement();
if (clazz != null) {
PsiClass mapClass = JavaPsiFacade.getInstance(getProject()).findClass(CommonClassNames.JAVA_UTIL_MAP, getResolveScope());
if (mapClass != null && mapClass.getTypeParameters().length == 2) {
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(mapClass, clazz, qResult.getSubstitutor());
if (substitutor != null) {
return TypeConversionUtil.erasure(substitutor.substitute(mapClass.getTypeParameters()[1]));
}
}
}
@@ -543,14 +572,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
}
}
if (result != null) {
result = TypesUtil.substituteBoxAndNormalizeType(result, resolveResult.getSubstitutor(), this);
}
if (dotType != mSPREAD_DOT) {
return result;
} else {
return ResolveUtil.getListTypeForSpreadOperator(this, result);
}
return null;
}
@Nullable
@@ -588,7 +610,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
if (!resolved.isValid()) {
throw new AssertionError("Invalid target of a valid reference");
}
return ((GrVariable) resolved).getTypeGroovy();
return ((GrVariable)resolved).getTypeGroovy();
}
}
@@ -598,7 +620,7 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
if (nominal == null) return inferred;
if (!TypeConversionUtil.isAssignable(nominal, inferred, false)) {
final PsiElement resolved = refExpr.resolve();
if (resolved instanceof GrVariable && ((GrVariable) resolved).getTypeElementGroovy() != null) {
if (resolved instanceof GrVariable && ((GrVariable)resolved).getTypeElementGroovy() != null) {
return nominal; //see GRVY-487
}
}
@@ -650,7 +672,8 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
return results;
default:
return GroovyResolveResult.EMPTY_ARRAY;
} }
}
}
private PsiType getThisType() {
GrExpression qualifier = getQualifierExpression();
@@ -755,13 +778,13 @@ public class GrReferenceExpressionImpl extends GrReferenceElementImpl<GrExpressi
public GroovyResolveResult advancedResolve() {
ResolveResult[] results = ResolveCache.getInstance(getProject()).resolveWithCaching(this, POLY_RESOLVER, true, false);
return results.length == 1 ? (GroovyResolveResult) results[0] : GroovyResolveResult.EMPTY_RESULT;
return results.length == 1 ? (GroovyResolveResult)results[0] : GroovyResolveResult.EMPTY_RESULT;
}
@NotNull
public GroovyResolveResult[] multiResolve(boolean incomplete) { //incomplete means we do not take arguments into consideration
final ResolveResult[] results = ResolveCache.getInstance(getProject()).resolveWithCaching(this, POLY_RESOLVER, true, incomplete);
return results.length == 0 ? GroovyResolveResult.EMPTY_ARRAY : (GroovyResolveResult[])results;
return results.length == 0 ? GroovyResolveResult.EMPTY_ARRAY : (GroovyResolveResult[])results;
}
@Override
@@ -18,9 +18,13 @@ package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions;
import com.intellij.psi.*;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.util.TypeConversionUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrThisReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
@@ -39,10 +43,11 @@ import static org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes.mSPREAD_D
* @author Medvedev Max
*/
public class GrReferenceResolveUtil {
private GrReferenceResolveUtil() {
}
public static boolean resolveImpl(ResolverProcessor processor, GrReferenceExpression place) {
static boolean resolveImpl(ResolverProcessor processor, GrReferenceExpression place) {
GrExpression qualifier = place.getQualifier();
if (qualifier == null) {
if (processor instanceof MethodResolverProcessor || processor instanceof CompletionProcessor) {
@@ -62,7 +67,14 @@ public class GrReferenceResolveUtil {
}
else {
if (place.getDotTokenType() == mSPREAD_DOT) {
if (!processQualifierForSpreadDot(processor, qualifier, place)) return false;
final PsiType qtype = qualifier.getType();
final PsiType componentType = getComponentTypeForSpreadDot(qtype, place);
if (componentType != null) {
final ResolveState state = ResolveState.initial()
.put(ResolverProcessor.RESOLVE_CONTEXT, qualifier)
.put(SpreadState.SPREAD_STATE, SpreadState.create(qtype, null));
if (!processQualifierType(processor, componentType, state, place)) return false;
}
}
else {
if (!processQualifier(processor, qualifier, place)) return false;
@@ -88,10 +100,10 @@ public class GrReferenceResolveUtil {
return true;
}
public static boolean processIfJavaLangClass(ResolverProcessor processor,
private static boolean processIfJavaLangClass(ResolverProcessor processor,
PsiType type,
GroovyPsiElement resolveContext,
GroovyPsiElement place) {
GrReferenceExpression place) {
if (!(type instanceof PsiClassType)) return true;
final PsiClass psiClass = ((PsiClassType)type).resolve();
@@ -100,70 +112,60 @@ public class GrReferenceResolveUtil {
final PsiType[] params = ((PsiClassType)type).getParameters();
if (params.length != 1) return true;
if (!processClassQualifierType(processor, params[0], resolveContext, place)) return false;
if (!processQualifierType(processor, params[0], ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext), place)) return false;
return true;
}
public static boolean processQualifierForSpreadDot(ResolverProcessor processor, GrExpression qualifier, GroovyPsiElement place) {
PsiType qualifierType = qualifier.getType();
@Nullable
private static PsiType getComponentTypeForSpreadDot(@Nullable PsiType qualifierType, @NotNull GroovyPsiElement place) {
if (qualifierType instanceof PsiArrayType) {
if (!processClassQualifierType(processor, ((PsiArrayType)qualifierType).getComponentType(), qualifier, place)) return false;
return true;
return ((PsiArrayType)qualifierType).getComponentType();
}
//process for collections
if (!(qualifierType instanceof PsiClassType)) return true;
if (!(qualifierType instanceof PsiClassType)) return null;
PsiClassType.ClassResolveResult result = ((PsiClassType)qualifierType).resolveGenerics();
PsiClass clazz = result.getElement();
if (clazz == null) return true;
if (clazz == null) return null;
PsiClass collection = GroovyPsiManager.getInstance(place.getProject())
.findClassWithCache(CommonClassNames.JAVA_UTIL_COLLECTION, place.getResolveScope());
if (collection == null || collection.getTypeParameters().length != 1) return true;
PsiClass collection = GroovyPsiManager.getInstance(place.getProject()).findClassWithCache(CommonClassNames.JAVA_UTIL_COLLECTION,
place.getResolveScope());
if (collection == null || collection.getTypeParameters().length != 1) return null;
PsiSubstitutor substitutor = TypeConversionUtil.getClassSubstitutor(collection, clazz, result.getSubstitutor());
if (substitutor == null) return true;
if (substitutor == null) return null;
PsiType componentType = substitutor.substitute(collection.getTypeParameters()[0]);
if (componentType == null) return true;
if (!processClassQualifierType(processor, componentType, qualifier, place)) return false;
return true;
return substitutor.substitute(collection.getTypeParameters()[0]);
}
public static boolean processQualifier(PsiScopeProcessor processor, GrExpression qualifier, GroovyPsiElement place) {
public static boolean processQualifier(PsiScopeProcessor processor, GrExpression qualifier, GrReferenceExpression place) {
PsiType qualifierType = qualifier.getType();
ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, qualifier);
if (qualifierType == null) {
if (qualifier instanceof GrReferenceExpression) {
PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
if (resolved instanceof PsiPackage) {
final ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, qualifier);
if (!resolved.processDeclarations(processor, state, null, place)) return false;
}
else {
qualifierType = TypesUtil.getJavaLangObject(place);
if (!processClassQualifierType(processor, qualifierType, qualifier, place)) return false;
if (!processQualifierType(processor, qualifierType, state, place)) return false;
}
}
}
else {
if (qualifierType instanceof PsiIntersectionType) {
for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
if (!processClassQualifierType(processor, conjunct, qualifier, place)) return false;
if (!processQualifierType(processor, conjunct, state, place)) return false;
}
}
else {
if (!processClassQualifierType(processor, qualifierType, qualifier, place)) return false;
if (!processQualifierType(processor, qualifierType, state, place)) return false;
if (qualifier instanceof GrReferenceExpression) {
PsiElement resolved = ((GrReferenceExpression)qualifier).resolve();
if (resolved instanceof PsiClass) { //omitted .class
PsiClass javaLangClass = PsiUtil.getJavaLangClass(resolved, place.getResolveScope());
if (javaLangClass != null) {
ResolveState state = ResolveState.initial();
PsiTypeParameter[] typeParameters = javaLangClass.getTypeParameters();
PsiSubstitutor substitutor = state.get(PsiSubstitutor.KEY);
if (substitutor == null) substitutor = PsiSubstitutor.EMPTY;
@@ -172,8 +174,7 @@ public class GrReferenceResolveUtil {
state = state.put(PsiSubstitutor.KEY, substitutor);
}
if (!javaLangClass.processDeclarations(processor, state, null, place)) return false;
PsiType javaLangClassType =
JavaPsiFacade.getInstance(place.getProject()).getElementFactory().createType(javaLangClass, substitutor);
PsiType javaLangClassType = TypesUtil.createJavaLangClassType(qualifierType, place.getProject(), place.getResolveScope());
if (!ResolveUtil.processNonCodeMembers(javaLangClassType, processor, place, state)) return false;
}
}
@@ -183,39 +184,42 @@ public class GrReferenceResolveUtil {
return true;
}
public static boolean processClassQualifierType(PsiScopeProcessor processor,
PsiType qualifierType,
GroovyPsiElement resolveContext,
GroovyPsiElement place) {
final ResolveState state;
if (qualifierType instanceof PsiDisjunctionType) {
qualifierType = ((PsiDisjunctionType)qualifierType).getLeastUpperBound();
private static boolean processQualifierType(final PsiScopeProcessor processor,
final PsiType originalQualifierType,
final ResolveState state,
final GrReferenceExpression place) {
PsiType qualifierType = originalQualifierType instanceof PsiDisjunctionType
? ((PsiDisjunctionType)originalQualifierType).getLeastUpperBound()
: originalQualifierType;
if (qualifierType instanceof PsiIntersectionType) {
for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
if (!processQualifierType(processor, conjunct, state, place)) return false;
}
return true;
}
if (qualifierType instanceof PsiClassType) {
PsiClassType.ClassResolveResult qualifierResult = ((PsiClassType)qualifierType).resolveGenerics();
PsiClass qualifierClass = qualifierResult.getElement();
state = ResolveState.initial().put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor())
.put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext);
if (qualifierClass != null) {
if (!qualifierClass.processDeclarations(processor, state, null, place)) return false;
if (!qualifierClass.processDeclarations(processor, state.put(PsiSubstitutor.KEY, qualifierResult.getSubstitutor()), null, place)) return false;
}
}
else if (qualifierType instanceof PsiArrayType) {
final GrTypeDefinition arrayClass = GroovyPsiManager.getInstance(place.getProject()).getArrayClass();
state = ResolveState.initial();
if (!arrayClass.processDeclarations(processor, state, null, place)) return false;
}
else if (qualifierType instanceof PsiIntersectionType) {
for (PsiType conjunct : ((PsiIntersectionType)qualifierType).getConjuncts()) {
if (!processClassQualifierType(processor, conjunct, resolveContext, place)) return false;
if (!(place.getParent() instanceof GrMethodCall)) {
final PsiType componentType = getComponentTypeForSpreadDot(qualifierType, place);
if (componentType != null) {
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
processQualifierType(processor, componentType, state.put(SpreadState.SPREAD_STATE, SpreadState.create(qualifierType, spreadState)), place);
}
return true;
}
else {
state = ResolveState.initial();
}
if (!ResolveUtil.processCategoryMembers(place, processor)) return false;
if (!ResolveUtil.processCategoryMembers(place, processor, state)) return false;
if (!ResolveUtil.processNonCodeMembers(qualifierType, processor, place, state)) return false;
return true;
}
@@ -35,6 +35,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GrTypeConverter;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrBinaryExpression;
@@ -688,14 +689,16 @@ public class TypesUtil {
@Nullable
public static PsiType substituteBoxAndNormalizeType(@Nullable PsiType type,
@NotNull PsiSubstitutor substitutor,
@NotNull GrExpression expression) {
@Nullable SpreadState state, @NotNull GrExpression expression) {
if (type == null) return null;
GlobalSearchScope resolveScope = expression.getResolveScope();
PsiManager manager = expression.getManager();
type = substitutor.substitute(type);
type = boxPrimitiveType(type, manager, resolveScope);
if (type == null) return null;
return PsiImplUtil.normalizeWildcardTypeByPosition(type, expression);
type = PsiImplUtil.normalizeWildcardTypeByPosition(type, expression);
type = SpreadState.apply(type, state, expression.getProject());
return type;
}
@Nullable
@@ -705,4 +708,48 @@ public class TypesUtil {
if (containerType instanceof PsiArrayType) return ((PsiArrayType)containerType).getComponentType();
return PsiUtil.extractIterableTypeParameter(containerType, false);
}
@Nullable
public static PsiClassType createSimilarCollection(PsiType collection, Project project, PsiType... itemType) {
if (InheritanceUtil.isInheritor(collection, "java.util.SortedSet")) {
return createCollection(project, "java.util.SortedSet", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedHashSet")) {
return createCollection(project, "java.util.LinkedHashSet", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Set")) {
return createCollection(project, "java.util.HashSet", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedList")) {
return createCollection(project, "java.util.LInkedList", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Stack")) {
return createCollection(project, "java.util.Stack", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Vector")) {
return createCollection(project, "java.util.Vector", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.List")) {
return createCollection(project, "java.util.ArrayList", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Queue")) {
return createCollection(project, "java.util.LinkedList", itemType);
}
return createCollection(project, "java.util.ArrayList", itemType);
}
@Nullable
private static PsiClassType createCollection(Project project, String collectionName, PsiType... item) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
PsiClass collection =
JavaPsiFacade.getInstance(project).findClass(collectionName, GlobalSearchScope.allScope(project));
if (collection == null) return null;
PsiTypeParameter[] parameters = collection.getTypeParameters();
if (parameters.length != 1) return null;
return factory.createType(collection, item);
}
}
@@ -21,7 +21,6 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.lexer.GroovyTokenTypes;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrVariable;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentList;
@@ -54,48 +53,56 @@ public class DefaultCallExpressionTypeCalculator extends GrCallExpressionTypeCal
PsiManager manager = callExpression.getManager();
PsiType result = null;
for (GroovyResolveResult resolveResult : resolveResults) {
PsiElement resolved = resolveResult.getElement();
PsiType returnType = null;
if (resolved instanceof PsiMethod) {
PsiMethod method = (PsiMethod) resolved;
if (resolveResult.isInvokedOnProperty()) {
final PsiType propertyType = PsiUtil.getSmartReturnType(method);
returnType = extractReturnTypeFromType(propertyType, true, callExpression);
} else {
returnType = getClosureMethodsReturnType(callExpression, refExpr, method);
if (returnType == null) {
returnType = PsiUtil.getSmartReturnType(method);
}
}
} else if (resolved instanceof GrVariable) {
PsiType refType = refExpr.getType();
final PsiType type = refType == null ? ((GrVariable) resolved).getTypeGroovy() : refType;
returnType = extractReturnTypeFromType(type, false, callExpression);
}
PsiType returnType = calculateReturnTypeInner(callExpression, refExpr, resolveResult);
if (returnType == null) return null;
if (!(returnType instanceof GrLiteralClassType)) {
returnType = TypesUtil.substituteBoxAndNormalizeType(returnType, resolveResult.getSubstitutor(), callExpression);
returnType = TypesUtil.substituteBoxAndNormalizeType(returnType, resolveResult.getSubstitutor(), resolveResult.getSpreadState(), callExpression);
LOG.assertTrue(returnType != null);
}
if (result == null || returnType.isAssignableFrom(result)) result = returnType;
else if (!result.isAssignableFrom(returnType))
if (result == null || returnType.isAssignableFrom(result)) {
result = returnType;
}
else if (!result.isAssignableFrom(returnType)) {
result = TypesUtil.getLeastUpperBound(result, returnType, manager);
}
}
if (result == null) return null;
if (refExpr.getDotTokenType() != GroovyTokenTypes.mSPREAD_DOT) {
return result;
} else {
return ResolveUtil.getListTypeForSpreadOperator(refExpr, result);
}
return result;
}
else {
return extractReturnTypeFromType(invoked.getType(), false, callExpression);
}
}
@Nullable
private static PsiType calculateReturnTypeInner(GrMethodCall callExpression,
GrReferenceExpression refExpr,
GroovyResolveResult resolveResult) {
PsiElement resolved = resolveResult.getElement();
PsiType returnType = null;
if (resolved instanceof PsiMethod) {
PsiMethod method = (PsiMethod)resolved;
if (resolveResult.isInvokedOnProperty()) {
final PsiType propertyType = PsiUtil.getSmartReturnType(method);
returnType = extractReturnTypeFromType(propertyType, true, callExpression);
}
else {
returnType = getClosureMethodsReturnType(callExpression, refExpr, method);
if (returnType == null) {
returnType = PsiUtil.getSmartReturnType(method);
}
}
}
else if (resolved instanceof GrVariable) {
PsiType refType = refExpr.getType();
final PsiType type = refType == null ? ((GrVariable)resolved).getTypeGroovy() : refType;
returnType = extractReturnTypeFromType(type, false, callExpression);
}
return returnType;
}
@Nullable
private static PsiType extractReturnTypeFromType(PsiType type, boolean returnTypeIfFail, GrMethodCall callExpression) {
PsiType returnType = returnTypeIfFail ? type: null;
@@ -15,10 +15,7 @@
*/
package org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.path;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
@@ -28,6 +25,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethod
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.typeEnhancers.GrCallExpressionTypeCalculator;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
@@ -82,7 +80,7 @@ public class GrDGMTypeCalculator extends GrCallExpressionTypeCalculator {
itemType = iitype;
}
}
return createSimilarCollection(type, callExpression.getProject(), itemType);
return TypesUtil.createSimilarCollection(type, callExpression.getProject(), itemType);
}
}
}
@@ -100,49 +98,6 @@ public class GrDGMTypeCalculator extends GrCallExpressionTypeCalculator {
}
}
@Nullable
private static PsiType createSimilarCollection(PsiType collection, Project project, PsiType... itemType) {
if (InheritanceUtil.isInheritor(collection, "java.util.SortedSet")) {
return createCollection(project, "java.util.SortedSet", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedHashSet")) {
return createCollection(project, "java.util.LinkedHashSet", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Set")) {
return createCollection(project, "java.util.HashSet", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.LinkedList")) {
return createCollection(project, "java.util.LInkedList", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Stack")) {
return createCollection(project, "java.util.Stack", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Vector")) {
return createCollection(project, "java.util.Vector", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.List")) {
return createCollection(project, "java.util.ArrayList", itemType);
}
if (InheritanceUtil.isInheritor(collection, "java.util.Queue")) {
return createCollection(project, "java.util.LinkedList", itemType);
}
return createCollection(project, "java.util.ArrayList", itemType);
}
@Nullable
private static PsiType createCollection(Project project, String collectionName, PsiType... item) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(project);
PsiClass collection =
JavaPsiFacade.getInstance(project).findClass(collectionName, GlobalSearchScope.allScope(project));
if (collection == null) return null;
PsiTypeParameter[] parameters = collection.getTypeParameters();
if (parameters.length != 1) return null;
return factory.createType(collection, item);
}
private static boolean isSimilarCollectionReturner(PsiMethod resolved) {
PsiParameter[] params = resolved.getParameterList().getParameters();
if (params.length == 0) return false;
@@ -270,7 +270,7 @@ public class GrIndexPropertyImpl extends GrExpressionImpl implements GrIndexProp
PsiParameter[] parameters = ((PsiMethod)element).getParameterList().getParameters();
if (parameters.length > 1) {
PsiParameter last = parameters[parameters.length - 1];
return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), this);
return TypesUtil.substituteBoxAndNormalizeType(last.getType(), candidate.getSubstitutor(), candidate.getSpreadState(), this);
}
}
return null;
@@ -102,8 +102,7 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant {
}
public GroovyResolveResult[] multiResolveClass() {
final PsiClass psiClass = getContainingClass();
GroovyResolveResult result = new GroovyResolveResultImpl(psiClass, this, PsiSubstitutor.EMPTY, true, true);
GroovyResolveResult result = new GroovyResolveResultImpl(getContainingClass(), this, null, PsiSubstitutor.EMPTY, true, true);
return new GroovyResolveResult[]{result};
}
@@ -135,7 +134,6 @@ public class GrEnumConstantImpl extends GrFieldImpl implements GrEnumConstant {
public GrExpression[] getExpressionArguments() {
final GrArgumentList argumentList = getArgumentList();
return argumentList == null ? GrExpression.EMPTY_ARRAY : argumentList.getExpressionArguments();
}
@NotNull
@@ -376,7 +376,7 @@ public class GrCodeReferenceElementImpl extends GrReferenceElementImpl<GrCodeRef
final PsiSubstitutor substitutor = result.getSubstitutor();
final PsiSubstitutor newSubstitutor = substitutor.putAll((PsiClass) element, args);
GroovyPsiElement context = result.getCurrentFileResolveContext();
GroovyResolveResultImpl newResult = new GroovyResolveResultImpl(element, context, newSubstitutor, result.isAccessible(), result.isStaticsOK());
GroovyResolveResultImpl newResult = new GroovyResolveResultImpl(element, context, null, newSubstitutor, result.isAccessible(), result.isStaticsOK());
results[i] = newResult;
if (context instanceof GrImportStatement) {
imported.add(newResult);
@@ -62,7 +62,7 @@ public class GdkMethodUtil {
private GdkMethodUtil() {
}
public static boolean categoryIteration(GrClosableBlock place, final PsiScopeProcessor processor) {
public static boolean categoryIteration(GrClosableBlock place, final PsiScopeProcessor processor, ResolveState state) {
final ClassHint classHint = processor.getHint(ClassHint.KEY);
if (classHint != null && !classHint.shouldProcess(ClassHint.ResolveKind.METHOD)) return true;
@@ -79,11 +79,12 @@ public class GdkMethodUtil {
if (!(call.resolveMethod() instanceof GrGdkMethod)) return true;
state = state.put(ResolverProcessor.RESOLVE_CONTEXT, call);
for (GrExpression arg : args) {
if (arg instanceof GrReferenceExpression) {
final PsiElement resolved = ((GrReferenceExpression)arg).resolve();
if (resolved instanceof PsiClass) {
if (!processCategoryMethods(place, processor, call, (PsiClass)resolved)) return false;
if (!processCategoryMethods(place, processor, state, (PsiClass)resolved)) return false;
}
}
}
@@ -100,7 +101,7 @@ public class GdkMethodUtil {
*/
public static boolean processCategoryMethods(final GroovyPsiElement place,
final PsiScopeProcessor processor,
@Nullable GroovyPsiElement resolveContext,
@NotNull ResolveState state,
@NotNull PsiClass categoryClass) {
final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) {
@Override
@@ -114,18 +115,17 @@ public class GdkMethodUtil {
return true;
}
};
final ResolveState state = ResolveState.initial().put(ResolverProcessor.RESOLVE_CONTEXT, resolveContext);
return categoryClass.processDeclarations(delegate, state, null, place);
}
public static boolean withIteration(GrClosableBlock block, final PsiScopeProcessor processor, GroovyPsiElement place) {
public static boolean withIteration(GrClosableBlock block, final PsiScopeProcessor processor) {
GrMethodCall call = checkMethodCall(block, WITH);
if (call == null) return true;
final GrExpression invoked = call.getInvokedExpression();
LOG.assertTrue(invoked instanceof GrReferenceExpression);
final GrExpression qualifier = ((GrReferenceExpression)invoked).getQualifier();
if (qualifier == null) return true;
if (!GrReferenceResolveUtil.processQualifier(processor, qualifier, place)) return false;
if (!GrReferenceResolveUtil.processQualifier(processor, qualifier, (GrReferenceExpression)invoked)) return false;
return true;
}
@@ -937,7 +937,7 @@ public class PsiUtil {
final GroovyResolveResult grResult = resolveResult instanceof GroovyResolveResult
? (GroovyResolveResult)resolveResult
: new GroovyResolveResultImpl(psiClass, context, substitutor, true, true);
: new GroovyResolveResultImpl(psiClass, context, null, substitutor, true, true);
return getConstructorCandidates(context, new GroovyResolveResult[]{grResult}, argTypes);
}
@@ -101,20 +101,20 @@ public class ResolveUtil {
}
if (doProcessNonCodeMembers) {
if (run instanceof GrTypeDefinition) {
if (!processNonCodeMembers(factory.createType(((GrTypeDefinition)run)), processor, place)) return false;
if (!processNonCodeMembers(factory.createType(((GrTypeDefinition)run)), processor, place, ResolveState.initial())) return false;
}
else if ((run instanceof GroovyFileBase) && ((GroovyFileBase)run).isScript()) {
final PsiClass psiClass = ((GroovyFileBase)run).getScriptClass();
if (psiClass != null) {
if (!processNonCodeMembers(factory.createType(psiClass), processor, place)) return false;
if (!processNonCodeMembers(factory.createType(psiClass), processor, place, ResolveState.initial())) return false;
}
}
else if (run instanceof GrClosableBlock) {
PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run);
if (superClass != null && !superClass.processDeclarations(processor, ResolveState.initial(), null, place)) return false;
if (!GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor)) return false;
if (!GdkMethodUtil.withIteration((GrClosableBlock)run, processor, place)) return false;
if (!GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor, ResolveState.initial())) return false;
if (!GdkMethodUtil.withIteration((GrClosableBlock)run, processor)) return false;
}
}
}
@@ -128,12 +128,12 @@ public class ResolveUtil {
public static boolean processChildren(PsiElement element,
PsiScopeProcessor processor,
ResolveState substitutor,
ResolveState state,
PsiElement lastParent,
PsiElement place) {
PsiElement run = lastParent == null ? element.getLastChild() : lastParent.getPrevSibling();
while (run != null) {
if (!run.processDeclarations(processor, substitutor, null, place)) return false;
if (!run.processDeclarations(processor, state, null, place)) return false;
run = run.getPrevSibling();
}
@@ -175,16 +175,10 @@ public class ResolveUtil {
}
}
if (!processNonCodeMembers(type, processor, place, state)) return false;
if (!processCategoryMembers(place, processor)) return false;
if (!processCategoryMembers(place, processor, state)) return false;
return true;
}
public static boolean processNonCodeMembers(PsiType type,
PsiScopeProcessor processor,
GroovyPsiElement place) {
return processNonCodeMembers(type, processor, place, ResolveState.initial());
}
public static boolean processNonCodeMembers(PsiType type,
PsiScopeProcessor processor,
GroovyPsiElement place,
@@ -277,21 +271,6 @@ public class ResolveUtil {
return result;
}
@Nullable
public static PsiType getListTypeForSpreadOperator(GrReferenceExpression refExpr, PsiType componentType) {
PsiClass clazz = JavaPsiFacade.getInstance(refExpr.getManager().getProject())
.findClass(CommonClassNames.JAVA_UTIL_LIST, refExpr.getResolveScope());
if (clazz != null) {
PsiTypeParameter[] typeParameters = clazz.getTypeParameters();
if (typeParameters.length == 1) {
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.put(typeParameters[0], componentType);
return JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory().createType(clazz, substitutor);
}
}
return null;
}
public static GroovyPsiElement resolveProperty(GroovyPsiElement place, String name) {
PropertyResolverProcessor processor = new PropertyResolverProcessor(name, place);
return resolveExistingElement(place, processor, GrVariable.class, GrReferenceExpression.class);
@@ -384,9 +363,9 @@ public class ResolveUtil {
return resolveLabelTargets(labelName, element, isBreak).first;
}
public static boolean processCategoryMembers(GroovyPsiElement place, PsiScopeProcessor processor) {
public static boolean processCategoryMembers(GroovyPsiElement place, PsiScopeProcessor processor, ResolveState state) {
boolean gpp = GppTypeConverter.hasTypedContext(place);
if (gpp && !processUseAnnotation(place, processor)) return false;
if (gpp && !processUseAnnotation(place, processor, state)) return false;
boolean inCodeBlock = true;
PsiElement run = place;
@@ -395,14 +374,15 @@ public class ResolveUtil {
inCodeBlock = false;
}
if (run instanceof GrClosableBlock) {
if (inCodeBlock && !GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor)) return false;
if (inCodeBlock && !GdkMethodUtil.categoryIteration((GrClosableBlock)run, processor, state)) return false;
PsiClass superClass = getLiteralSuperClass((GrClosableBlock)run);
if (superClass != null && !GdkMethodUtil.processCategoryMethods(((GrClosableBlock)run), processor, null, superClass)) return false;
if (superClass != null && !GdkMethodUtil.processCategoryMethods(((GrClosableBlock)run), processor, state, superClass)) return false;
}
if (gpp && run instanceof GrTypeDefinition) {
final GrTypeDefinition typeDefinition = (GrTypeDefinition)run;
if (!GdkMethodUtil.processCategoryMethods(typeDefinition, processor, typeDefinition, typeDefinition)) return false;
state = state.put(ResolverProcessor.RESOLVE_CONTEXT, typeDefinition);
if (!GdkMethodUtil.processCategoryMethods(typeDefinition, processor, state, typeDefinition)) return false;
}
run = run.getContext();
}
@@ -410,13 +390,13 @@ public class ResolveUtil {
return true;
}
private static boolean processUseAnnotation(GroovyPsiElement place, PsiScopeProcessor processor) {
private static boolean processUseAnnotation(GroovyPsiElement place, PsiScopeProcessor processor, ResolveState state) {
PsiAnnotation use = AnnotatedContextFilter.findContextAnnotation(place, GroovyCommonClassNames.GROOVY_LANG_USE);
if (use != null) {
for (PsiElement element : PsiElementCategory.asList(use.findDeclaredAttributeValue("value"))) {
if (element instanceof GrReferenceExpression) {
PsiElement resolve = ((GrReferenceExpression)element).resolve();
if (resolve instanceof PsiClass && !GdkMethodUtil.processCategoryMethods(place, processor, null, (PsiClass)resolve)) {
if (resolve instanceof PsiClass && !GdkMethodUtil.processCategoryMethods(place, processor, state, (PsiClass)resolve)) {
return false;
}
}
@@ -687,7 +667,7 @@ public class ResolveUtil {
public static PsiType extractReturnTypeFromCandidate(GroovyResolveResult candidate, GrExpression expression, @Nullable PsiType[] args) {
final PsiElement element = candidate.getElement();
if (element instanceof PsiMethod && !candidate.isInvokedOnProperty()) {
return TypesUtil.substituteBoxAndNormalizeType(getSmartReturnType((PsiMethod)element), candidate.getSubstitutor(), expression);
return TypesUtil.substituteBoxAndNormalizeType(getSmartReturnType((PsiMethod)element), candidate.getSubstitutor(), candidate.getSpreadState(), expression);
}
final PsiType type;
@@ -703,7 +683,7 @@ public class ResolveUtil {
if (type instanceof GrClosureType) {
final GrSignature signature = ((GrClosureType)type).getSignature();
PsiType returnType = GrClosureSignatureUtil.getReturnType(signature, args, expression);
return TypesUtil.substituteBoxAndNormalizeType(returnType, candidate.getSubstitutor(), expression);
return TypesUtil.substituteBoxAndNormalizeType(returnType, candidate.getSubstitutor(), candidate.getSpreadState(), expression);
}
return null;
}
@@ -20,6 +20,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
@@ -78,9 +79,10 @@ public class AccessorResolverProcessor extends MethodResolverProcessor {
}
boolean isAccessible = isAccessible(method);
final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
boolean isStaticsOK = isStaticsOK(method, resolveContext, true);
final GroovyResolveResultImpl candidate =
new GroovyResolveResultImpl(method, resolveContext, substitutor, isAccessible, isStaticsOK, true);
new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK, true);
if (isAccessible && isStaticsOK) {
addCandidate(candidate);
return method instanceof GrGdkMethod; //don't stop searching if we found only gdk method
@@ -27,6 +27,7 @@ import org.jetbrains.plugins.groovy.gpp.GppClosureParameterTypeProvider;
import org.jetbrains.plugins.groovy.gpp.GppTypeConverter;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.signatures.GrClosureSignature;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrGdkMethod;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyResolveResultImpl;
@@ -100,12 +101,14 @@ public class MethodResolverProcessor extends ResolverProcessor {
}
boolean isAccessible = isAccessible(method);
GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
boolean isStaticsOK = isStaticsOK(method, resolveContext, true);
if (!myAllVariants && isStaticsOK && isAccessible &&
PsiUtil.isApplicable(myArgumentTypes, method, substitutor, (GroovyPsiElement)myPlace, myByShape)) {
addCandidate(new GroovyResolveResultImpl(method, resolveContext, substitutor, isAccessible, isStaticsOK));
addCandidate(new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
} else {
myInapplicableCandidates.add(new GroovyResolveResultImpl(method, resolveContext, substitutor, isAccessible, isStaticsOK));
myInapplicableCandidates.add(new GroovyResolveResultImpl(method, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
}
return true;
@@ -26,6 +26,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.GroovyResolveResult;
import org.jetbrains.plugins.groovy.lang.psi.api.SpreadState;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrField;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.GrAccessorMethod;
@@ -97,8 +98,9 @@ public class ResolverProcessor implements PsiScopeProcessor, NameHint, ClassHint
boolean isAccessible = isAccessible(namedElement);
final GroovyPsiElement resolveContext = state.get(RESOLVE_CONTEXT);
final SpreadState spreadState = state.get(SpreadState.SPREAD_STATE);
boolean isStaticsOK = isStaticsOK(namedElement, resolveContext, true);
addCandidate(new GroovyResolveResultImpl(namedElement, resolveContext, substitutor, isAccessible, isStaticsOK));
addCandidate(new GroovyResolveResultImpl(namedElement, resolveContext, spreadState, substitutor, isAccessible, isStaticsOK));
return !isAccessible || !isStaticsOK;
}
@@ -180,7 +180,7 @@ public class ResolveMethodTest extends GroovyResolveTestCase {
assertTrue(type instanceof PsiClassType);
PsiClass clazz = ((PsiClassType) type).resolve();
assertNotNull(clazz);
assertEquals("java.util.List", clazz.getQualifiedName());
assertEquals("java.util.ArrayList", clazz.getQualifiedName());
}
@@ -426,6 +426,57 @@ print ma<caret>p
''', "$JAVA_UTIL_MAP<$JAVA_LANG_STRING,$JAVA_LANG_STRING>")
}
void testSpread1() {
myFixture.addClass('''\
class A {
String getString() {return "a";}
}''')
doTest('''\
[new A()].stri<caret>ng
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>")
}
void testSpread2() {
myFixture.addClass('''\
class A {
String getString() {return "a";}
}''')
doTest('''\
class Cat {
static getFoo(String b) {2}
}
use(Cat) {
[new A()].string.fo<caret>o
}
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>")
}
void testSpread3() {
myFixture.addClass('''\
class A {
String getString() {return "a";}
}''')
doTest('''\
[[new A()]].stri<caret>ng
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_STRING>>")
}
void testSpread4() {
myFixture.addClass('''\
class A {
String getString() {return "a";}
}''')
doTest('''\
class Cat {
static getFoo(String b) {2}
}
use(Cat){
[[new A()]].string.fo<caret>o
}
''', "$JAVA_UTIL_ARRAY_LIST<$JAVA_UTIL_ARRAY_LIST<$JAVA_LANG_INTEGER>>")
}
private void doTest(String text, String type) {
def file = myFixture.configureByText('_.groovy', text)
@@ -1050,11 +1050,9 @@ public class MethodEntry extends ClassContentsEntry implements RelatableEntry {
return;
}
createAlternateValueString();
/**
* we don't want to check for comments in the body of the method. So reduce the alternate value string
* to only that text up to and including the open brace. Temporarily remove the rest of the text; append
* it again after checking for comments.
*/
// We don't want to check for comments in the body of the method. So reduce the alternate value string
// to only that text up to and including the open brace. Temporarily remove the rest of the text; append
// it again after checking for comments.
int brace = myAlternateValue.indexOf('{');
String temp = "";
if (brace >= 0) {
@@ -361,7 +361,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setGlobalCommentPattern(String globalCommentPattern) {
this.myGlobalCommentPattern = globalCommentPattern;
myGlobalCommentPattern = globalCommentPattern;
}
// end of Level 2 methods
@@ -384,7 +384,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setOverloadedOrder(int overloadedOrder) {
this.myOverloadedOrder = overloadedOrder;
myOverloadedOrder = overloadedOrder;
}
// end of Level 2 methods
@@ -403,7 +403,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setAskBeforeRearranging(boolean askBeforeRearranging) {
this.myAskBeforeRearranging = askBeforeRearranging;
myAskBeforeRearranging = askBeforeRearranging;
}
public boolean isKeepGettersSettersTogether() {
@@ -413,7 +413,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setKeepGettersSettersTogether(boolean keepGettersSettersTogether) {
this.myKeepGettersSettersTogether = keepGettersSettersTogether;
myKeepGettersSettersTogether = keepGettersSettersTogether;
}
public boolean isKeepGettersSettersWithProperty() {
@@ -421,7 +421,7 @@ public final class RearrangerSettings {
}
public void setKeepGettersSettersWithProperty(boolean keepGettersSettersWithProperty) {
this.myKeepGettersSettersWithProperty = keepGettersSettersWithProperty;
myKeepGettersSettersWithProperty = keepGettersSettersWithProperty;
}
// end of Level 2 methods
// end of Level 1 methods
@@ -434,7 +434,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setKeepOverloadedMethodsTogether(boolean keepOverloadedMethodsTogether) {
this.myKeepOverloadedMethodsTogether = keepOverloadedMethodsTogether;
myKeepOverloadedMethodsTogether = keepOverloadedMethodsTogether;
}
// end of Level 2 methods
@@ -445,7 +445,7 @@ public final class RearrangerSettings {
}
public void setRearrangeInnerClasses(boolean rearrangeInnerClasses) {
this.myRearrangeInnerClasses = rearrangeInnerClasses;
myRearrangeInnerClasses = rearrangeInnerClasses;
}
// end of Level 2 methods
@@ -459,7 +459,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setRemoveBlanksInsideCodeBlocks(boolean removeBlanksInsideCodeBlocks) {
this.myRemoveBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks;
myRemoveBlanksInsideCodeBlocks = removeBlanksInsideCodeBlocks;
}
public boolean isShowComments() {
@@ -467,7 +467,7 @@ public final class RearrangerSettings {
}
public void setShowComments(boolean showComments) {
this.myShowComments = showComments;
myShowComments = showComments;
}
// end of Level 2 methods
@@ -481,7 +481,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setShowFields(boolean showFields) {
this.myShowFields = showFields;
myShowFields = showFields;
}
public boolean isShowMatchedRules() {
@@ -489,7 +489,7 @@ public final class RearrangerSettings {
}
public void setShowMatchedRules(boolean showMatchedRules) {
this.myShowMatchedRules = showMatchedRules;
myShowMatchedRules = showMatchedRules;
}
public boolean isShowParameterNames() {
@@ -499,7 +499,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setShowParameterNames(boolean showParameterNames) {
this.myShowParameterNames = showParameterNames;
myShowParameterNames = showParameterNames;
}
// end of Level 2 methods
@@ -513,7 +513,7 @@ public final class RearrangerSettings {
// Level 2 methods
public void setShowParameterTypes(boolean showParameterTypes) {
this.myShowParameterTypes = showParameterTypes;
myShowParameterTypes = showParameterTypes;
}
// end of Level 2 methods
@@ -524,7 +524,7 @@ public final class RearrangerSettings {
}
public void setShowRules(boolean showRules) {
this.myShowRules = showRules;
myShowRules = showRules;
}
// end of Level 2 methods
@@ -534,7 +534,7 @@ public final class RearrangerSettings {
}
public void setShowTypeAfterMethod(boolean showTypeAfterMethod) {
this.myShowTypeAfterMethod = showTypeAfterMethod;
myShowTypeAfterMethod = showTypeAfterMethod;
}
// ------------------------ CANONICAL METHODS ------------------------
@@ -160,15 +160,13 @@ class RearrangerTest extends LightCodeInsightFixtureTestCase {
testOpsBlockingQueueExampleWorker(false, "OpsBlockingQueue", false, "OpsBlockingQueue");
}
// public final void testOpsBlockingQueueExampleWithGlobalPattern() throws Exception {
// testOpsBlockingQueueExampleWorker(true, "/com/wrq/rearranger/OpsBlockingQueue.java",
// false, "/com/wrq/rearranger/OpsBlockingQueue.java");
// }
//
// public final void testOpsBlockingQueueExampleWithIndentedComments() throws Exception {
// testOpsBlockingQueueExampleWorker(false, "/com/wrq/rearranger/OpsBlockingQueueIndented.java",
// true, "/com/wrq/rearranger/OpsBlockingQueueIndentedResult.java");
// }
public final void testOpsBlockingQueueExampleWithGlobalPattern() throws Exception {
testOpsBlockingQueueExampleWorker(true, "OpsBlockingQueue", false, "OpsBlockingQueue");
}
public final void testOpsBlockingQueueExampleWithIndentedComments() throws Exception {
testOpsBlockingQueueExampleWorker(false, "OpsBlockingQueueIndented", true, "OpsBlockingQueueIndentedResult");
}
private void testOpsBlockingQueueExampleWorker(boolean doGlobalPattern,
String srcFilename,
@@ -294,36 +292,42 @@ class RearrangerTest extends LightCodeInsightFixtureTestCase {
}
}
// public final void testReturnTypeMatch() throws Exception {
// configureByFile("/com/wrq/rearranger/RearrangementTest12.java");
// final PsiFile file = getFile();
// final Document doc = PsiDocumentManager.getInstance(getProject()).getDocument(file);
// MethodAttributes ma;
// ma = new MethodAttributes();
// ma.getReturnTypeAttr().setMatch(true);
// ma.getReturnTypeAttr().setExpression("void");
// rs.addItem(ma, 0);
// FieldAttributes fa = new FieldAttributes();
// fa.getTypeAttr().setMatch(true);
// fa.getTypeAttr().setExpression("int");
// rs.addItem(fa, 1);
// ma = new MethodAttributes();
// ma.getReturnTypeAttr().setMatch(true);
// ma.getReturnTypeAttr().setExpression(".*je.*");
// rs.addItem(ma, 2);
// ma = new MethodAttributes();
// ma.getReturnTypeAttr().setMatch(true);
// ma.getReturnTypeAttr().setExpression("Integer\\[\\]");
// rs.addItem(ma, 3);
// ma = new MethodAttributes();
// ma.getReturnTypeAttr().setMatch(true);
// ma.getReturnTypeAttr().setExpression("int");
// rs.addItem(ma, 4);
// final RearrangerActionHandler rah = new RearrangerActionHandler();
// rah.rearrangeDocument(getProject(), file, rs, doc);
// super.checkResultByFile("/com/wrq/rearranger/RearrangementResult12.java");
// }
//
public final void testReturnTypeMatch() throws Exception {
doTest('RearrangementTest12', 'RearrangementResult12') {
methodRule.create { returnType( 'void' ) }
fieldRule.create { type( 'int' ) }
methodRule.create { returnType( '.*je.*' ) }
methodRule.create { returnType( /Integer\[\]/) }
methodRule.create { returnType( 'int' ) }
}
//MethodAttributes ma;
//ma = new MethodAttributes();
//ma.getReturnTypeAttr().setMatch(true);
//ma.getReturnTypeAttr().setExpression("void");
//rs.addItem(ma, 0);
//FieldAttributes fa = new FieldAttributes();
//fa.getTypeAttr().setMatch(true);
//fa.getTypeAttr().setExpression("int");
//rs.addItem(fa, 1);
//ma = new MethodAttributes();
//ma.getReturnTypeAttr().setMatch(true);
//ma.getReturnTypeAttr().setExpression(".*je.*");
//rs.addItem(ma, 2);
//ma = new MethodAttributes();
//ma.getReturnTypeAttr().setMatch(true);
//ma.getReturnTypeAttr().setExpression("Integer\\[\\]");
//rs.addItem(ma, 3);
//ma = new MethodAttributes();
//ma.getReturnTypeAttr().setMatch(true);
//ma.getReturnTypeAttr().setExpression("int");
//rs.addItem(ma, 4);
//final RearrangerActionHandler rah = new RearrangerActionHandler();
//rah.rearrangeDocument(getProject(), file, rs, doc);
//super.checkResultByFile("/com/wrq/rearranger/RearrangementResult12.java");
}
// public final void testRelatedMethodsDepthOriginal() throws Exception {
// configureByFile("/com/wrq/rearranger/RearrangementTest13.java");
// final PsiFile file = getFile();
@@ -16,6 +16,8 @@ public enum RearrangerTestDsl {
INITIALIZER,
/** Method target type (e.g. constructor). */
TARGET,
TYPE,
RETURN_TYPE("returnType"),
SORT,
COMMENT,
@@ -14,6 +14,7 @@ class JavaFieldRuleBuilder extends AbstractJavaRuleBuilder<FieldAttributes> {
{
def handlers = [(InitializerType.ANONYMOUS_CLASS) : createBooleanAttributeHandler('initialisedByAnonymousClassAttr')]
registerHandler(RearrangerTestDsl.INITIALIZER, { data, attributes, rule -> handlers[data](attributes, rule) })
registerHandler(RearrangerTestDsl.TYPE, createStringAttributeHandler('typeAttr'))
}
@Override
@@ -18,6 +18,7 @@ class JavaMethodRuleBuilder extends AbstractJavaRuleBuilder<MethodAttributes> {
(MethodType.OTHER) : createRawBooleanAttributeHandler('otherMethodType')
]
registerHandler(RearrangerTestDsl.TARGET, { data, attributes, rule -> handlers[data](attributes, rule) })
registerHandler(RearrangerTestDsl.RETURN_TYPE, createStringAttributeHandler('returnTypeAttr'))
}
@Override
@@ -10,22 +10,20 @@ import opsx.server.email.OpsEmailGenerator;
/** @author dchan */
public class OpsBlockingQueue extends OpsNonBlockingQueue {
//*********************************** PROTECTED/PACKAGE FIELDS **************************************
//*********************************** PROTECTED/PACKAGE FIELDS **************************************
protected final Object putLock;
protected final Object takeLock;
protected volatile int waitCount;
//************************************** PRIVATE FIELDS *****************************************
//************************************** PRIVATE FIELDS *****************************************
private static final OpsLogCategory logCat = (OpsLogCategory)OpsLogCategory.getInstance(OpsEmailGenerator.class);
//************************************** CONSTRUCTORS *************************************
/** Creates new OpsBlockingQueue */
public OpsBlockingQueue() {
takeLock = new Object();
putLock = new Object();
waitCount = 0;
}
//************************************** PUBLIC METHODS *************************************
//************************************** PUBLIC METHODS *************************************
// PUBLIC METHODS LINE 2
public void put(Object obj) {
synchronized (putLock) {
@@ -61,8 +59,7 @@ public class OpsBlockingQueue extends OpsNonBlockingQueue {
}
}
}
//********************************* PACKAGE/PROTECTED METHODS ********************************
//********************************* PACKAGE/PROTECTED METHODS ********************************
protected Object takeNext() {
synchronized (takeLock) {
return super.takeNext();
@@ -1,9 +1,9 @@
class RearrangementTest12 {
void method(int y) {
x = y;
}
int x;
int x;
Object convertX() {
return new Integer(x);
@@ -16,6 +16,5 @@ class RearrangementTest12 {
int getX() {
return x;
}
String s;
}