mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 11:50:54 +07:00
create annotation method from usage (IDEA-75910 )
This commit is contained in:
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.CodeInsightUtilBase;
|
||||
import com.intellij.codeInsight.daemon.JavaErrorMessages;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfoType;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.CreateAnnotationMethodFromUsageFix;
|
||||
import com.intellij.codeInsight.daemon.impl.quickfix.QuickFixAction;
|
||||
import com.intellij.codeInsight.intention.IntentionAction;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -51,8 +52,10 @@ public class AnnotationsHighlightUtil {
|
||||
PsiMethod method = (PsiMethod)ref.resolve();
|
||||
if (method == null) {
|
||||
if (pair.getName() != null) {
|
||||
String description = JavaErrorMessages.message("annotation.unknown.method", ref.getCanonicalText());
|
||||
return HighlightInfo.createHighlightInfo(HighlightInfoType.WRONG_REF, ref.getElement(), description);
|
||||
final String description = JavaErrorMessages.message("annotation.unknown.method", ref.getCanonicalText());
|
||||
final HighlightInfo highlightInfo = HighlightInfo.createHighlightInfo(HighlightInfoType.WRONG_REF, ref.getElement(), description);
|
||||
QuickFixAction.registerQuickFixAction(highlightInfo, new CreateAnnotationMethodFromUsageFix(pair));
|
||||
return highlightInfo;
|
||||
}
|
||||
else {
|
||||
String description = JavaErrorMessages.message("annotation.missing.method", ref.getCanonicalText());
|
||||
@@ -334,8 +337,8 @@ public class AnnotationsHighlightUtil {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static class AnnotationReturnTypeVisitor extends PsiTypeVisitor<Boolean> {
|
||||
private static final AnnotationReturnTypeVisitor INSTANCE = new AnnotationReturnTypeVisitor();
|
||||
public static class AnnotationReturnTypeVisitor extends PsiTypeVisitor<Boolean> {
|
||||
public static final AnnotationReturnTypeVisitor INSTANCE = new AnnotationReturnTypeVisitor();
|
||||
public Boolean visitType(PsiType type) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.codeInsight.daemon.impl.quickfix;
|
||||
|
||||
import com.intellij.codeInsight.ExpectedTypeInfo;
|
||||
import com.intellij.codeInsight.ExpectedTypesProvider;
|
||||
import com.intellij.codeInsight.TailType;
|
||||
import com.intellij.codeInsight.daemon.QuickFixBundle;
|
||||
import com.intellij.codeInsight.daemon.impl.analysis.AnnotationsHighlightUtil;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class CreateAnnotationMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
private static final Logger LOG = Logger.getInstance("#" + CreateAnnotationMethodFromUsageFix.class.getName());
|
||||
|
||||
private final SmartPsiElementPointer<PsiNameValuePair> myNameValuePair;
|
||||
|
||||
public CreateAnnotationMethodFromUsageFix(PsiNameValuePair valuePair) {
|
||||
myNameValuePair = SmartPointerManager.getInstance(valuePair.getProject()).createSmartPsiElementPointer(valuePair);
|
||||
}
|
||||
|
||||
protected boolean isAvailableImpl(int offset) {
|
||||
final PsiNameValuePair call = getNameValuePair();
|
||||
if (call == null || !call.isValid()) return false;
|
||||
String name = call.getName();
|
||||
|
||||
if (name == null || !JavaPsiFacade.getInstance(call.getProject()).getNameHelper().isIdentifier(name)) return false;
|
||||
if (getAnnotationValueType(call.getValue()) == null) return false;
|
||||
setText(QuickFixBundle.message("create.method.from.usage.text", name));
|
||||
return true;
|
||||
}
|
||||
|
||||
protected PsiElement getElement() {
|
||||
final PsiNameValuePair call = getNameValuePair();
|
||||
if (call == null || !call.getManager().isInProject(call)) return null;
|
||||
return call;
|
||||
}
|
||||
|
||||
protected void invokeImpl(final PsiClass targetClass) {
|
||||
if (targetClass == null) return;
|
||||
|
||||
PsiNameValuePair nameValuePair = getNameValuePair();
|
||||
if (nameValuePair == null || isValidElement(nameValuePair)) return;
|
||||
|
||||
final PsiElementFactory factory = JavaPsiFacade.getInstance(nameValuePair.getProject()).getElementFactory();
|
||||
|
||||
final String methodName = nameValuePair.getName();
|
||||
LOG.assertTrue(methodName != null);
|
||||
|
||||
PsiMethod method = factory.createMethod(methodName, PsiType.VOID);
|
||||
|
||||
method = (PsiMethod)targetClass.add(method);
|
||||
|
||||
PsiCodeBlock body = method.getBody();
|
||||
assert body != null;
|
||||
body.delete();
|
||||
|
||||
final PsiElement context = PsiTreeUtil.getParentOfType(nameValuePair, PsiClass.class, PsiMethod.class);
|
||||
|
||||
final PsiType type = getAnnotationValueType(nameValuePair.getValue());
|
||||
LOG.assertTrue(type != null);
|
||||
final ExpectedTypeInfo[] expectedTypes =
|
||||
new ExpectedTypeInfo[]{ExpectedTypesProvider.createInfo(type, ExpectedTypeInfo.TYPE_OR_SUBTYPE, type, TailType.NONE)};
|
||||
CreateMethodFromUsageFix.doCreate(targetClass, method, true, ContainerUtil.map2List(PsiExpression.EMPTY_ARRAY, Pair.<PsiExpression, PsiType>createFunction(null)),
|
||||
getTargetSubstitutor(nameValuePair), expectedTypes, context);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType getAnnotationValueType(PsiAnnotationMemberValue value) {
|
||||
PsiType type = null;
|
||||
if (value instanceof PsiExpression) {
|
||||
type = ((PsiExpression)value).getType();
|
||||
} else if (value instanceof PsiArrayInitializerMemberValue) {
|
||||
final PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers();
|
||||
PsiType currentType = null;
|
||||
for (PsiAnnotationMemberValue initializer : initializers) {
|
||||
if (initializer instanceof PsiArrayInitializerMemberValue) return null;
|
||||
if (!(initializer instanceof PsiExpression)) return null;
|
||||
final PsiType psiType = ((PsiExpression)initializer).getType();
|
||||
if (psiType != null) {
|
||||
if (currentType == null) {
|
||||
currentType = psiType;
|
||||
} else {
|
||||
if (!TypeConversionUtil.isAssignable(currentType, psiType)) {
|
||||
if (TypeConversionUtil.isAssignable(psiType, currentType)) {
|
||||
currentType = psiType;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (currentType != null) {
|
||||
type = currentType.createArrayType();
|
||||
}
|
||||
}
|
||||
if (type != null && type.accept(AnnotationsHighlightUtil.AnnotationReturnTypeVisitor.INSTANCE).booleanValue()) {
|
||||
return type;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected boolean isValidElement(PsiElement element) {
|
||||
final PsiReference reference = element.getReference();
|
||||
return reference != null && reference.resolve() != null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return QuickFixBundle.message("create.method.from.usage.family");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected PsiNameValuePair getNameValuePair() {
|
||||
return myNameValuePair.getElement();
|
||||
}
|
||||
}
|
||||
@@ -249,6 +249,24 @@ public abstract class CreateFromUsageBaseFix extends BaseIntentionAction {
|
||||
PsiClass psiClass = null;
|
||||
PsiExpression qualifier = null;
|
||||
|
||||
if (element instanceof PsiNameValuePair) {
|
||||
final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(element, PsiAnnotation.class);
|
||||
if (annotation != null) {
|
||||
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
|
||||
if (nameRef == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
else {
|
||||
final PsiElement resolve = nameRef.resolve();
|
||||
if (resolve instanceof PsiClass) {
|
||||
return Collections.singletonList((PsiClass)resolve);
|
||||
}
|
||||
else {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiNewExpression) {
|
||||
final PsiNewExpression newExpression = (PsiNewExpression)element;
|
||||
PsiJavaCodeReferenceElement ref = newExpression.getClassOrAnonymousClassReference();
|
||||
|
||||
@@ -196,7 +196,7 @@ public class CreateMethodFromUsageFix extends CreateFromUsageBaseFix {
|
||||
doCreate(targetClass, method, shouldBeAbstractImpl(targetClass), arguments, substitutor, expectedTypes, context);
|
||||
}
|
||||
|
||||
private static void doCreate(PsiClass targetClass,
|
||||
public static void doCreate(PsiClass targetClass,
|
||||
PsiMethod method,
|
||||
boolean shouldBeAbstract,
|
||||
List<Pair<PsiExpression, PsiType>> arguments,
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Create Method 'test'" "true"
|
||||
public class Test {
|
||||
@Attr(test= "")
|
||||
public Test() {
|
||||
}
|
||||
}
|
||||
|
||||
@interface Attr {
|
||||
String test();
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
// "Create Method 'test'" "true"
|
||||
public class Test {
|
||||
@Attr(test= {""})
|
||||
public Test() {
|
||||
}
|
||||
}
|
||||
|
||||
@interface Attr {
|
||||
String[] test();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Create Method 'test'" "true"
|
||||
public class Test {
|
||||
@Attr(te<caret>st= "")
|
||||
public Test() {
|
||||
}
|
||||
}
|
||||
|
||||
@interface Attr {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Create Method 'test'" "true"
|
||||
public class Test {
|
||||
@Attr(te<caret>st= {""})
|
||||
public Test() {
|
||||
}
|
||||
}
|
||||
|
||||
@interface Attr {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Create Method 'test'" "false"
|
||||
public class Test {
|
||||
@Attr(te<caret>st= {"", 1})
|
||||
public Test() {
|
||||
}
|
||||
}
|
||||
|
||||
@interface Attr {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// "Create Method 'test'" "false"
|
||||
public class Test {
|
||||
@Attr(te<caret>st= {new String[]{""}})
|
||||
public Test() {
|
||||
}
|
||||
}
|
||||
|
||||
@interface Attr {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2000-2011 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.codeInsight.daemon.quickFix;
|
||||
|
||||
public class CreateAnnotationMethodFromUsageTest extends LightQuickFix15TestCase {
|
||||
public void test() throws Exception { doAllTests(); }
|
||||
|
||||
@Override
|
||||
protected String getBasePath() {
|
||||
return "/codeInsight/daemonCodeAnalyzer/quickFix/createAnnotationMethodFromUsage";
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user