Merge remote branch 'origin/master'

This commit is contained in:
irengrig
2012-05-30 16:21:16 +04:00
20 changed files with 384 additions and 85 deletions
@@ -80,9 +80,11 @@ public class CreateNewLibraryAction extends DumbAwareAction {
@NotNull final Project project, @NotNull final LibrariesModifiableModel modifiableModel) {
final NewLibraryConfiguration configuration = createNewLibraryConfiguration(type, parentComponent, project);
if (configuration == null) return null;
final Library library = modifiableModel.createLibrary(LibraryEditingUtil.suggestNewLibraryName(modifiableModel, configuration.getDefaultLibraryName()), configuration.getLibraryType().getKind());
final LibraryType<?> libraryType = configuration.getLibraryType();
final Library library = modifiableModel.createLibrary(
LibraryEditingUtil.suggestNewLibraryName(modifiableModel, configuration.getDefaultLibraryName()), libraryType != null ? libraryType.getKind() : null);
final NewLibraryEditor editor = new NewLibraryEditor(configuration.getLibraryType(), configuration.getProperties());
final NewLibraryEditor editor = new NewLibraryEditor(libraryType, configuration.getProperties());
configuration.addRoots(editor);
final Library.ModifiableModel model = library.getModifiableModel();
editor.applyTo((LibraryEx.ModifiableModelEx)model);
@@ -61,11 +61,11 @@ public class ChangeParameterClassFix extends ExtendsListFix {
@NotNull PsiElement startElement,
@NotNull PsiElement endElement) {
return
super.isAvailable(project, file, startElement, endElement)
&& myClassToExtendFrom != null
&& myClassToExtendFrom.isValid()
&& myClassToExtendFrom.getQualifiedName() != null
;
super.isAvailable(project, file, startElement, endElement)
&& myClassToExtendFrom != null
&& myClassToExtendFrom.isValid()
&& myClassToExtendFrom.getQualifiedName() != null
;
}
@Override
@@ -115,17 +115,20 @@ public class ChangeParameterClassFix extends ExtendsListFix {
}
public static void registerQuickFixAction(PsiVariable variable, PsiType returnType, HighlightInfo info) {
final PsiClass psiClass = PsiUtil.resolveClassInClassTypeOnly(returnType);
final PsiClass returnClass = PsiUtil.resolveClassInClassTypeOnly(returnType);
final PsiType variableType = variable.getType();
final PsiClass variableClass = PsiUtil.resolveClassInClassTypeOnly(variableType);
if (psiClass != null && variableClass != null && !psiClass.isInheritor(variableClass, true)) {
QuickFixAction.registerQuickFixAction(info, new ChangeParameterClassFix(psiClass, (PsiClassType)variableType));
}
if (returnClass == null || variableClass == null) return;
if (returnClass instanceof PsiAnonymousClass) return;
if (returnClass.isInheritor(variableClass, true)) return;
QuickFixAction.registerQuickFixAction(info, new ChangeParameterClassFix(returnClass, (PsiClassType)variableType));
}
public static void registerQuickFixActions(PsiCall methodCall, PsiExpressionList list, HighlightInfo highlightInfo) {
final JavaResolveResult result = methodCall.resolveMethodGenerics();
PsiMethod method = (PsiMethod) result.getElement();
PsiMethod method = (PsiMethod)result.getElement();
final PsiSubstitutor substitutor = result.getSubstitutor();
PsiExpression[] expressions = list.getExpressions();
if (method == null || method.getParameterList().getParametersCount() != expressions.length) return;
@@ -134,12 +137,13 @@ public class ChangeParameterClassFix extends ExtendsListFix {
PsiParameter parameter = method.getParameterList().getParameters()[i];
PsiType expressionType = expression.getType();
PsiType parameterType = substitutor.substitute(parameter.getType());
if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType ) continue;
if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType ) continue;
if (expressionType == null || expressionType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(expressionType) || expressionType instanceof PsiArrayType) continue;
if (parameterType instanceof PsiPrimitiveType || TypeConversionUtil.isNullType(parameterType) || parameterType instanceof PsiArrayType) continue;
if (parameterType.isAssignableFrom(expressionType)) continue;
PsiClass parameterClass = PsiUtil.resolveClassInType(parameterType);
PsiClass expressionClass = PsiUtil.resolveClassInType(expressionType);
if (parameterClass == null || expressionClass == null) continue;
if (expressionClass instanceof PsiAnonymousClass) continue;
if (parameterClass.isInheritor(expressionClass, true)) continue;
QuickFixAction.registerQuickFixAction(highlightInfo, new ChangeParameterClassFix(expressionClass, (PsiClassType)parameterType));
}
@@ -412,7 +412,7 @@ public class InlineMethodProcessor extends BaseRefactoringProcessor {
}
}
private void inlineMethodCall(PsiReferenceExpression ref) throws IncorrectOperationException {
public void inlineMethodCall(PsiReferenceExpression ref) throws IncorrectOperationException {
InlineUtil.TailCallType tailCall = InlineUtil.getTailCallType(ref);
ChangeContextUtil.encodeContextInfo(myMethod, false);
myMethodCopy = (PsiMethod)myMethod.copy();
@@ -72,7 +72,7 @@ public class InlineSuperCallUsageInfo extends FixableUsageInfo {
assert inliningClass != null;
methodCopy = (PsiMethod)inliningClass.add(methodCopy);
final InlineMethodProcessor inlineMethodProcessor = new InlineMethodProcessor(getProject(), methodCopy, methodExpression, null, true);
inlineMethodProcessor.run();
inlineMethodProcessor.inlineMethodCall(methodExpression);
methodCopy.delete();
}
}
@@ -30,6 +30,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
@@ -356,7 +357,8 @@ public class PushDownProcessor extends BaseRefactoringProcessor {
}
else if (member instanceof PsiMethod) {
PsiMethod method = (PsiMethod)member;
final PsiMethod methodBySignature = targetClass.findMethodBySignature(method, false);
final PsiMethod methodBySignature =
MethodSignatureUtil.findMethodBySuperSignature(targetClass, method.getSignature(substitutor), false);
if (methodBySignature == null) {
final boolean wasInterface = myClass.isInterface();
newMember = (PsiMethod)targetClass.add(method);
@@ -0,0 +1,14 @@
// "Make 'null' implement 'Foo.IBar'" "false"
public abstract class Foo {
static Foo anonymous = new Foo() {
@Override
void fooMethod() {
foo2Method(th<caret>is);
}
};
protected Foo() {
IBar bar = anonymou<caret>s;
}
}
@@ -0,0 +1,19 @@
// "Make 'null' implement 'Foo.IBar'" "false"
public abstract class Foo {
public static interface IBar {
void barMethod();
}
abstract void fooMethod();
void foo2Method(IBar b) {
}
static Foo anonymous = new Foo() {
@Override
void fooMethod() {
foo2Method(th<caret>is);
}
};
}
@@ -0,0 +1,13 @@
abstract class BaseTask<T, S extends BaseTask<T, S>> {
public abstract S make<caret>Task(int depth, ParallelStream<T> coll);
}
class ForEachTask<T> extends BaseTask<T, ForEachTask<T>> {
public ForEachTask<T> makeTask(int depth, ParallelStream<T> coll) {
return new ForEachTask<T>();
}
}
class ParallelStream<T> {
}
@@ -0,0 +1,12 @@
abstract class BaseTask<T, S extends BaseTask<T, S>> {
}
class ForEachTask<T> extends BaseTask<T, ForEachTask<T>> {
public ForEachTask<T> makeTask(int depth, ParallelStream<T> coll) {
return new ForEachTask<T>();
}
}
class ParallelStream<T> {
}
@@ -115,6 +115,10 @@ public class PushDownTest extends LightRefactoringTestCase {
doTest();
}
public void testOverridingMethodWithSubst() throws Exception {
doTest();
}
public void testSameClassInterface() throws Exception {
final String filePath = "/refactoring/pushDown/" + getTestName(false) + ".java";
configureByFile(filePath);
@@ -846,7 +846,7 @@ public class Mappings {
}
private class Differential {
static final int DESPERATE_MASK = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
final int DESPERATE_MASK = Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
final Mappings myDelta;
final Collection<String> myRemoved;
@@ -994,7 +994,7 @@ public class Mappings {
}
}
private void processAddedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private void processAddedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing added methods: ");
for (final MethodRepr m : diff.methods().added()) {
debug("Method: ", m.name);
@@ -1120,7 +1120,7 @@ public class Mappings {
debug("End of added methods processing");
}
private void processRemovedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private void processRemovedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing removed methods:");
for (final MethodRepr m : diff.methods().removed()) {
debug("Method ", m.name);
@@ -1216,7 +1216,7 @@ public class Mappings {
debug("End of removed methods processing");
}
private void processChangedMethods (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private void processChangedMethods(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing changed methods:");
for (final Pair<MethodRepr, Difference> mr : diff.methods().changed()) {
final MethodRepr m = mr.first;
@@ -1305,7 +1305,7 @@ public class Mappings {
debug("End of changed methods processing");
}
private boolean processAddedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private boolean processAddedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing added fields");
for (final FieldRepr f : diff.fields().added()) {
@@ -1407,7 +1407,7 @@ public class Mappings {
return true;
}
private boolean processRemovedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private boolean processRemovedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing removed fields:");
for (final FieldRepr f : diff.fields().removed()) {
@@ -1434,7 +1434,7 @@ public class Mappings {
return true;
}
private boolean processChangedFields (final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
private boolean processChangedFields(final DiffState state, final ClassRepr.Diff diff, final ClassRepr it) {
debug("Processing changed fields:");
for (final Pair<FieldRepr, Difference> f : diff.fields().changed()) {
@@ -1623,19 +1623,19 @@ public class Mappings {
debug("End of annotation-specific analysis");
}
processAddedMethods (state, diff, it);
processRemovedMethods (state, diff, it);
processChangedMethods (state, diff, it);
processAddedMethods(state, diff, it);
processRemovedMethods(state, diff, it);
processChangedMethods(state, diff, it);
if (!processAddedFields (state, diff, it)) {
if (!processAddedFields(state, diff, it)) {
return false;
}
if (!processRemovedFields (state, diff, it)) {
if (!processRemovedFields(state, diff, it)) {
return false;
}
if (!processChangedFields (state, diff, it)) {
if (!processChangedFields(state, diff, it)) {
return false;
}
}
@@ -1880,6 +1880,16 @@ public class Mappings {
}
if (delta.myIsDifferentiated) {
final TIntHashSet compiledClasses = new TIntHashSet();
delta.myClassToSourceFile.forEachEntry(new TIntIntProcedure() {
@Override
public boolean execute(final int a, final int b) {
compiledClasses.add(a);
return true;
}
});
for (ClassRepr repr : delta.getDeletedClasses()) {
cleanupRemovedClass(repr, null, subclassesTrashBin, dependenciesTrashBin);
}
@@ -1895,13 +1905,31 @@ public class Mappings {
delta.getChangedClasses().forEach(new TIntProcedure() {
@Override
public boolean execute(int className) {
final TIntHashSet subClasses = delta.myClassToSubclasses.get(className);
if (subClasses != null) {
myClassToSubclasses.replace(className, subClasses);
public boolean execute(final int className) {
TIntHashSet s = delta.myClassToSubclasses.get(className);
final TIntHashSet newSubClasses = s == null ? new TIntHashSet() : s;
final TIntHashSet oldSubClasses = myClassToSubclasses.get(className);
if (oldSubClasses != null) {
oldSubClasses.forEach(new TIntProcedure() {
@Override
public boolean execute(final int value) {
if (!compiledClasses.contains(value)) {
newSubClasses.add(value);
}
return true;
}
}
);
}
if (newSubClasses.size() == 0) {
myClassToSubclasses.remove(className);
}
else {
myClassToSubclasses.remove(className);
myClassToSubclasses.replace(className, newSubClasses);
}
final int sourceFile = delta.myClassToSourceFile.get(className);
@@ -204,6 +204,17 @@ public class VfsUtilCore {
}
}
@NotNull
public static String loadText(@NotNull VirtualFile file, int length) throws IOException{
InputStreamReader reader = new InputStreamReader(file.getInputStream(), file.getCharset());
try {
return new String(FileUtil.loadText(reader, length));
}
finally {
reader.close();
}
}
@NotNull
public static VirtualFile[] toVirtualFileArray(@NotNull Collection<? extends VirtualFile> files) {
int size = files.size();
@@ -23,6 +23,8 @@ import com.intellij.openapi.command.undo.DocumentReferenceManager;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.TextRange;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.io.OutputStream;
@@ -31,7 +33,7 @@ import java.io.OutputStream;
* @author traff
*/
public class ConsoleExecuteActionHandler {
private final ProcessHandler myProcessHandler;
private ProcessHandler myProcessHandler;
private final boolean myPreserveMarkup;
private boolean myAddCurrentToHistory = true;
private ConsoleHistoryModel myConsoleHistoryModel;
@@ -42,6 +44,15 @@ public class ConsoleExecuteActionHandler {
myPreserveMarkup = preserveMarkup;
}
@Nullable
private synchronized ProcessHandler getProcessHandler() {
return myProcessHandler;
}
public synchronized void setProcessHandler(@NotNull final ProcessHandler processHandler) {
myProcessHandler = processHandler;
}
public void setConsoleHistoryModel(ConsoleHistoryModel consoleHistoryModel) {
myConsoleHistoryModel = consoleHistoryModel;
}
@@ -81,7 +92,10 @@ public class ConsoleExecuteActionHandler {
public void sendText(String line) {
//final Charset charset = myProcessHandler.getCharset();
final OutputStream outputStream = myProcessHandler.getProcessInput();
final ProcessHandler handler = getProcessHandler();
assert handler != null : "process handler is null";
final OutputStream outputStream = handler.getProcessInput();
assert outputStream != null : "output stream is null";
try {
//byte[] bytes = (line + "\n").getBytes(charset.name());
byte[] bytes = line.getBytes();
@@ -100,6 +114,11 @@ public class ConsoleExecuteActionHandler {
public void finishExecution() {
}
public final boolean isProcessTerminated() {
final ProcessHandler handler = getProcessHandler();
return handler == null || handler.isProcessTerminated();
}
public String getEmptyExecuteAction() {
return "Console.Execute";
}
@@ -60,8 +60,10 @@ import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.annotator.intentions.*;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicMethodFix;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.DynamicPropertyFix;
import org.jetbrains.plugins.groovy.codeInspection.assignment.GroovyAssignabilityCheckInspection;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
import org.jetbrains.plugins.groovy.debugger.fragments.GroovyCodeFragment;
import org.jetbrains.plugins.groovy.dsl.toplevel.AnnotatedContextFilter;
import org.jetbrains.plugins.groovy.extensions.GroovyUnresolvedHighlightFilter;
import org.jetbrains.plugins.groovy.highlighter.DefaultHighlighter;
import org.jetbrains.plugins.groovy.lang.documentation.GroovyPresentationUtil;
@@ -101,12 +103,14 @@ import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatem
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.packaging.GrPackageDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.types.*;
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrVariableDeclarationOwner;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.TypeInferenceHelper;
import org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GrLightParameter;
import org.jetbrains.plugins.groovy.lang.psi.impl.synthetic.GroovyScriptClass;
import org.jetbrains.plugins.groovy.lang.psi.util.GrStringUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyCommonClassNames;
import org.jetbrains.plugins.groovy.lang.psi.util.GroovyPropertyUtils;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -128,6 +132,9 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
if (element instanceof GroovyPsiElement) {
myHolder = holder;
((GroovyPsiElement)element).accept(this);
if (isCompileStatic(element)) {
GroovyAssignabilityCheckInspection.checkElement((GroovyPsiElement)element, holder);
}
myHolder = null;
}
else {
@@ -324,6 +331,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement resolved = resolveResult.getElement();
final PsiElement parent = referenceExpression.getParent();
if (resolved != null) {
if (resolved instanceof PsiMember) {
highlightMemberResolved(myHolder, referenceExpression, ((PsiMember)resolved));
@@ -337,7 +345,7 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
Annotation annotation = myHolder.createInfoAnnotation(referenceExpression,
GroovyBundle.message("cannot.reference.nonstatic",
referenceExpression.getReferenceName()));
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
annotation.setTextAttributes(isStaticallyCompiled(referenceExpression)?DefaultHighlighter.BAD_CHARACTER:DefaultHighlighter.UNRESOLVED_ACCESS);
}
}
}
@@ -377,8 +385,22 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
PsiElement refNameElement = referenceExpression.getReferenceNameElement();
PsiElement elt = refNameElement == null ? referenceExpression : refNameElement;
Annotation annotation = myHolder.createInfoAnnotation(elt, null);
final GrExpression qualifier = referenceExpression.getQualifierExpression();
Annotation annotation;
boolean compileStatic = isCompileStatic(referenceExpression);
if (compileStatic) {
annotation = myHolder.createInfoAnnotation(elt, GroovyBundle.message("cannot.resolve", referenceExpression.getReferenceName()));
annotation.setHighlightType(ProblemHighlightType.LIKE_UNKNOWN_SYMBOL);
}
else {
if (qualifier != null && qualifier.getType() == null) return;
annotation = myHolder.createInfoAnnotation(elt, null);
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
}
if (qualifier == null) {
if (parent instanceof GrMethodCall) {
registerStaticImportFix(referenceExpression, annotation);
@@ -388,20 +410,22 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
registerAddImportFixes(referenceExpression, annotation);
}
}
else {
if (qualifier.getType() == null) {
return;
}
}
registerReferenceFixes(referenceExpression, annotation);
registerReferenceFixes(referenceExpression, annotation, compileStatic);
UnresolvedReferenceQuickFixProvider.registerReferenceFixes(referenceExpression, new QuickFixActionRegistrarAdapter(annotation));
OrderEntryFix.registerFixes(new QuickFixActionRegistrarAdapter(annotation), referenceExpression);
annotation.setTextAttributes(DefaultHighlighter.UNRESOLVED_ACCESS);
}
}
private static boolean isCompileStatic(PsiElement e) {
PsiMember containingMember = PsiTreeUtil.getParentOfType(e, PsiMember.class);
return containingMember != null && GroovyPsiManager.getInstance(containingMember.getProject()).isCompileStatic(containingMember);
}
private static boolean isStaticallyCompiled(GrReferenceExpression referenceExpression) {
return AnnotatedContextFilter.findContextAnnotation(referenceExpression, GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC)!=null;
}
private void highlightVariable(GrVariable variable, PsiElement toHighlight) {
Annotation annotation = myHolder.createInfoAnnotation(toHighlight, null);
boolean reassigned = isReassigned(variable);
@@ -1772,11 +1796,13 @@ public class GroovyAnnotator extends GroovyElementVisitor implements Annotator {
}
private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation) {
PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr);
private static void registerReferenceFixes(GrReferenceExpression refExpr, Annotation annotation, boolean compileStatic) {
PsiClass targetClass = QuickfixUtil.findTargetClass(refExpr, compileStatic);
if (targetClass == null) return;
addDynamicAnnotation(annotation, refExpr);
if (!compileStatic) {
addDynamicAnnotation(annotation, refExpr);
}
if (targetClass.isWritable()) {
if (!(targetClass instanceof GroovyScriptClass)) {
if (targetClass instanceof GrMemberOwner) {
@@ -26,7 +26,6 @@ import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
import com.intellij.psi.codeStyle.SuggestedNameInfo;
import com.intellij.psi.codeStyle.VariableKind;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.util.ArrayUtil;
import gnu.trove.THashSet;
@@ -34,13 +33,13 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ParamInfo;
import org.jetbrains.plugins.groovy.annotator.intentions.dynamic.ui.DynamicElementSettings;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFileBase;
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElement;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrArgumentLabel;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrCall;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
import org.jetbrains.plugins.groovy.lang.psi.util.PsiUtil;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
@@ -53,22 +52,13 @@ import java.util.*;
*/
public class QuickfixUtil {
@Nullable
public static PsiClass findTargetClass(GrReferenceExpression refExpr) {
final PsiClass psiClass;
if (refExpr.isQualified()) {
GrExpression qualifier = refExpr.getQualifierExpression();
PsiType type = qualifier.getType();
if (!(type instanceof PsiClassType)) return null;
psiClass = ((PsiClassType)type).resolve();
} else {
GroovyPsiElement context = PsiTreeUtil.getParentOfType(refExpr, GrTypeDefinition.class, GroovyFileBase.class);
if (context instanceof GrTypeDefinition) {
return (PsiClass)context;
} else if (context instanceof GroovyFileBase) return ((GroovyFileBase)context).getScriptClass();
return null;
public static PsiClass findTargetClass(GrReferenceExpression refExpr, boolean compileStatic) {
PsiType type = GrReferenceResolveUtil.getQualifierType(refExpr);
if (type == null && compileStatic) {
return GroovyPsiManager.getInstance(refExpr.getProject()).findClassWithCache(CommonClassNames.JAVA_LANG_OBJECT, refExpr.getResolveScope());
}
return psiClass;
if (!(type instanceof PsiClassType)) return null;
return ((PsiClassType)type).resolve();
}
public static boolean isStaticCall(GrReferenceExpression refExpr) {
@@ -184,7 +174,7 @@ public class QuickfixUtil {
public static DynamicElementSettings createSettings(GrReferenceExpression referenceExpression) {
DynamicElementSettings settings = new DynamicElementSettings();
final PsiClass containingClass = findTargetClass(referenceExpression);
final PsiClass containingClass = findTargetClass(referenceExpression, false);
assert containingClass != null;
String className = containingClass.getQualifiedName();
@@ -16,14 +16,22 @@
package org.jetbrains.plugins.groovy.codeInspection.assignment;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.InspectionManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.codeInspection.ProblemDescriptor;
import com.intellij.codeInspection.ProblemHighlightType;
import com.intellij.lang.annotation.Annotation;
import com.intellij.lang.annotation.AnnotationHolder;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -31,7 +39,6 @@ import org.jetbrains.plugins.groovy.GroovyBundle;
import org.jetbrains.plugins.groovy.annotator.GroovyAnnotator;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspection;
import org.jetbrains.plugins.groovy.codeInspection.BaseInspectionVisitor;
import org.jetbrains.plugins.groovy.codeInspection.GroovyFix;
import org.jetbrains.plugins.groovy.codeInspection.GroovyInspectionBundle;
import org.jetbrains.plugins.groovy.codeInspection.utils.ControlFlowUtils;
import org.jetbrains.plugins.groovy.config.GroovyConfigUtils;
@@ -45,6 +52,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.auxiliary.GrListOrMap;
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.GrConstructorInvocation;
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.arguments.GrArgumentList;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.arguments.GrNamedArgument;
@@ -56,10 +64,12 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.*;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.literals.GrString;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrIndexProperty;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.GrTypeDefinition;
import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.controlFlow.Instruction;
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
@@ -80,11 +90,6 @@ import java.util.Map;
public class GroovyAssignabilityCheckInspection extends BaseInspection {
private static final Logger LOG = Logger.getInstance(GroovyAssignabilityCheckInspection.class);
@Override
protected GroovyFix buildFix(PsiElement location) {
return super.buildFix(location); //To change body of overridden methods use File | Settings | File Templates.
}
@Nls
@NotNull
@Override
@@ -159,6 +164,8 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
@Override
public void visitMethod(GrMethod method) {
if (GroovyPsiManager.getInstance(method.getProject()).isCompileStatic(method)) return;
super.visitMethod(method);
final GrOpenBlock block = method.getBlock();
if (block == null) return;
@@ -178,6 +185,18 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
});
}
@Override
public void visitField(GrField field) {
if (GroovyPsiManager.getInstance(field.getProject()).isCompileStatic(field)) return;
super.visitField(field);
}
@Override
public void visitTypeDefinition(GrTypeDefinition typeDefinition) {
if (GroovyPsiManager.getInstance(typeDefinition.getProject()).isCompileStatic(typeDefinition)) return;
super.visitTypeDefinition(typeDefinition);
}
@Override
public void visitReturnStatement(GrReturnStatement returnStatement) {
super.visitReturnStatement(returnStatement);
@@ -761,4 +780,75 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
}
return GrReferenceResolveUtil.getQualifierType(place);
}
private static class AnnotatingVisitor extends MyVisitor {
private AnnotationHolder myHolder;
@Override
protected void registerError(@NotNull final PsiElement location,
final String description,
final LocalQuickFix[] fixes,
final ProblemHighlightType highlightType) {
Annotation annotation = myHolder.createErrorAnnotation(location, description);
for (final LocalQuickFix fix : fixes) {
annotation.registerFix(new IntentionAction() {
@NotNull
@Override
public String getText() {
return fix.getName();
}
@NotNull
@Override
public String getFamilyName() {
return fix.getFamilyName();
}
@Override
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
return true;
}
@Override
public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
InspectionManager manager = InspectionManager.getInstance(project);
ProblemDescriptor descriptor = manager.createProblemDescriptor(location, description, fixes, highlightType, fixes.length == 1, false);
fix.applyFix(project, descriptor);
}
@Override
public boolean startInWriteAction() {
return true;
}
});
}
}
@Override
public void visitElement(GroovyPsiElement element) {
//do nothing
}
}
private static final ThreadLocal<AnnotatingVisitor> visitor = new ThreadLocal<AnnotatingVisitor>() {
@Override
protected AnnotatingVisitor initialValue() {
return new AnnotatingVisitor();
}
};
public static void checkElement(GroovyPsiElement e, AnnotationHolder holder) {
AnnotatingVisitor annotatingVisitor = visitor.get();
AnnotationHolder oldHolder = annotatingVisitor.myHolder;
try {
annotatingVisitor.myHolder = holder;
e.accept(annotatingVisitor);
}
finally {
annotatingVisitor.myHolder = oldHolder;
}
}
}
@@ -77,15 +77,9 @@ public class GroovyBraceEnforcer extends GroovyRecursiveElementVisitor {
// if (true) i = 1; // Cool assignment
// We can't just surround target block of code with curly braces because the closing one will be treated as comment as well.
// Hence, we perform a check if we have such situation at the moment and insert new line before the closing brace.
int lastLineFeedIndex = oldText.lastIndexOf("\n");
lastLineFeedIndex = Math.max(0, lastLineFeedIndex);
int lastLineCommentIndex = oldText.indexOf("//", lastLineFeedIndex);
StringBuilder buf = new StringBuilder(oldText.length() + 5);
buf.append("{ ").append(oldText);
if (lastLineCommentIndex >= 0) {
buf.append("\n");
}
buf.append(" }");
buf.append("{\n").append(oldText);
buf.append("\n}");
final int oldTextLength = statement.getTextLength();
try {
CodeEditUtil.replaceChild(SourceTreeToPsiMap.psiElementToTree(statement),
@@ -65,6 +65,7 @@ public class GroovyPsiManager {
private final ConcurrentMap<GroovyPsiElement, PsiType> myCalculatedTypes = new ConcurrentWeakHashMap<GroovyPsiElement, PsiType>();
private final ConcurrentMap<String, SoftReference<Map<GlobalSearchScope, PsiClass>>> myClassCache = new ConcurrentHashMap<String, SoftReference<Map<GlobalSearchScope, PsiClass>>>();
private final ConcurrentMap<PsiMember, Boolean> myCompileStatic = new ConcurrentHashMap<PsiMember, Boolean>();
private static final RecursionGuard ourGuard = RecursionManager.createGuard("groovyPsiManager");
@@ -92,6 +93,7 @@ public class GroovyPsiManager {
public void dropTypesCache() {
myCalculatedTypes.clear();
myCompileStatic.clear();
}
public static boolean isInheritorCached(@Nullable PsiClass aClass, @NotNull String baseClassName) {
@@ -122,6 +124,25 @@ public class GroovyPsiManager {
return JavaPsiFacade.getElementFactory(myProject).createTypeByFQClassName(fqName, resolveScope);
}
public boolean isCompileStatic(PsiMember member) {
Boolean aBoolean = myCompileStatic.get(member);
if (aBoolean == null) {
aBoolean = ConcurrencyUtil.cacheOrGet(myCompileStatic, member, isCompileStaticInner(member));
}
return aBoolean;
}
private boolean isCompileStaticInner(PsiMember member) {
PsiModifierList list = member.getModifierList();
if (list != null) {
PsiAnnotation annotation = list.findAnnotation(GroovyCommonClassNames.GROOVY_TRANSFORM_COMPILE_STATIC);
if (annotation != null) return true;
}
PsiClass aClass = member.getContainingClass();
if (aClass != null) return isCompileStatic(aClass);
return false;
}
@Nullable
public PsiClass findClassWithCache(String fqName, GlobalSearchScope resolveScope) {
SoftReference<Map<GlobalSearchScope, PsiClass>> reference = myClassCache.get(fqName);
@@ -50,7 +50,8 @@ public final class GroovyCommonClassNames {
@NonNls public static final String GROOVY_LANG_USE = "groovy.lang.Use";
@NonNls public static final String GROOVY_LANG_MIXIN = "groovy.lang.Mixin";
@NonNls public static final String GROOVY_UTIL_TEST_CASE = "groovy.util.GroovyTestCase";
public static final String GROOVY_LANG_SINGLETON = "groovy.lang.Singleton";
@NonNls public static final String GROOVY_LANG_SINGLETON = "groovy.lang.Singleton";
@NonNls public static final String GROOVY_TRANSFORM_COMPILE_STATIC = "groovy.transform.CompileStatic";
private GroovyCommonClassNames() {
@@ -1009,4 +1009,53 @@ use(Ca) {
''', GroovyAssignabilityCheckInspection)
}
void testCompileStatic() {
myFixture.addClass('''\
package groovy.transform;
public @interface CompileStatic {
}''')
myFixture.configureByText('_.groovy', '''\
<info descr="null">import</info> <info descr="null">groovy.transform.CompileStatic</info>
<info descr="null">class</info> <info descr="null">A</info> {
<info descr="null">def</info> <info descr="null">foo</info>() {
<info descr="null">print</info> <info descr="null">abc</info>
}
<info descr="null">@CompileStatic</info>
<info descr="null">def</info> <info descr="null">bar</info>() {
<info descr="null">print</info> <info descr="Cannot resolve symbol 'abc'">abc</info>
}
}
''')
myFixture.testHighlighting(true, true, true)
}
void testCompileStaticWithAssignabilityCheck() {
myFixture.addClass('''\
package groovy.transform;
public @interface CompileStatic {
}''')
myFixture.configureByText('_.groovy', '''\
import groovy.transform.CompileStatic
class A {
def foo(String s) {
int x = <warning descr="Cannot assign 'Date' to 'int'">new Date()</warning>
}
@CompileStatic
def bar() {
int x = <error descr="Cannot assign 'Date' to 'int'">new Date()</error>
}
}
''')
myFixture.enableInspections(GroovyAssignabilityCheckInspection)
myFixture.checkHighlighting(true, false, true)
}
}