Magic constant inspection

This commit is contained in:
Alexey Kudravtsev
2012-01-12 16:29:10 +04:00
parent d966eef1fa
commit a87146dc5b
15 changed files with 1670 additions and 49 deletions

View File

@@ -145,7 +145,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
if (document == null) continue;
final XmlTag rootTag = document.getRootTag();
if (rootTag == null) continue;
final String externalName = PsiFormatUtil.getExternalName(listOwner, false);
final String externalName = getExternalName(listOwner, false);
final String oldExternalName = getNormalizedExternalName(listOwner);
for (final XmlTag tag : rootTag.getSubTags()) {
final String className = tag.getAttributeValue("name");
@@ -179,6 +179,10 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
return result;
}
private static String getExternalName(PsiModifierListOwner listOwner, boolean showParamName) {
return PsiFormatUtil.getExternalName(listOwner, showParamName, Integer.MAX_VALUE);
}
public void annotateExternally(@NotNull final PsiModifierListOwner listOwner,
@NotNull final String annotationFQName,
@@ -317,7 +321,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
if (document != null) {
final XmlTag rootTag = document.getRootTag();
if (rootTag != null) {
final String externalName = PsiFormatUtil.getExternalName(listOwner, false);
final String externalName = getExternalName(listOwner, false);
final String oldExternalName = getNormalizedExternalName(listOwner);
for (final XmlTag tag : rootTag.getSubTags()) {
final String className = tag.getAttributeValue("name");
@@ -445,7 +449,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
final XmlDocument document = xmlFile.getDocument();
if (document != null) {
final XmlTag rootTag = document.getRootTag();
final String externalName = PsiFormatUtil.getExternalName(listOwner, false);
final String externalName = getExternalName(listOwner, false);
if (rootTag != null) {
for (XmlTag tag : rootTag.getSubTags()) {
if (Comparing.strEqual(tag.getAttributeValue("name"), externalName)) {
@@ -603,7 +607,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager {
@Nullable
private static String getNormalizedExternalName(PsiModifierListOwner owner) {
String externalName = PsiFormatUtil.getExternalName(owner);
String externalName = getExternalName(owner, true);
if (externalName != null) {
if (owner instanceof PsiParameter && owner.getParent() instanceof PsiParameterList) {
final PsiMethod method = PsiTreeUtil.getParentOfType(owner, PsiMethod.class);

View File

@@ -0,0 +1,181 @@
/*
* 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.codeInspection.magicConstant;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.lookup.LookupItemUtil;
import com.intellij.codeInsight.lookup.VariableLookupItem;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.ArrayUtil;
import com.intellij.util.Consumer;
import gnu.trove.THashSet;
import gnu.trove.TObjectHashingStrategy;
import java.util.Set;
import static com.intellij.patterns.PlatformPatterns.psiElement;
public class MagicCompletionContributor extends CompletionContributor {
private static final ElementPattern<PsiElement> IN_METHOD_CALL_ARGUMENT =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiExpressionList.class).withParent(PsiCall.class)));
private static final ElementPattern<PsiElement> IN_BINARY_COMPARISON =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiBinaryExpression.class)));
private static final ElementPattern<PsiElement> IN_ASSIGNMENT =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiAssignmentExpression.class)));
private static final ElementPattern<PsiElement> IN_RETURN =
psiElement().withParent(psiElement(PsiReferenceExpression.class).inside(psiElement(PsiReturnStatement.class)));
private static final ElementPattern<PsiElement> IN_ANNOTATION_INITIALIZER =
psiElement().afterLeaf("=").withParent(PsiReferenceExpression.class).withSuperParent(2,PsiNameValuePair.class).withSuperParent(3,PsiAnnotationParameterList.class).withSuperParent(4,PsiAnnotation.class);
private static final int PRIORITY = 100;
@Override
public void fillCompletionVariants(final CompletionParameters parameters, final CompletionResultSet result) {
//if (parameters.getCompletionType() != CompletionType.SMART) return;
PsiElement pos = parameters.getPosition();
MagicConstantInspection.AllowedValues allowedValues = null;
if (IN_METHOD_CALL_ARGUMENT.accepts(pos)) {
PsiCall call = PsiTreeUtil.getParentOfType(pos, PsiCall.class);
if (!(call instanceof PsiExpression)) return;
PsiType type = ((PsiExpression)call).getType();
PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(call.getProject()).getResolveHelper();
JavaResolveResult[] methods = call instanceof PsiMethodCallExpression
? ((PsiMethodCallExpression)call).getMethodExpression().multiResolve(true)
: call instanceof PsiNewExpression && type instanceof PsiClassType
? resolveHelper.multiResolveConstructor((PsiClassType)type, call.getArgumentList(), call)
: JavaResolveResult.EMPTY_ARRAY;
for (JavaResolveResult resolveResult : methods) {
PsiElement element = resolveResult.getElement();
if (!(element instanceof PsiMethod)) return;
PsiMethod method = (PsiMethod)element;
if (!resolveHelper.isAccessible(method, call, null)) continue;
PsiElement argument = pos;
while (!(argument.getParent() instanceof PsiExpressionList)) argument = argument.getParent();
PsiExpressionList list = (PsiExpressionList)argument.getParent();
int i = ArrayUtil.indexOf(list.getExpressions(), argument);
if (i == -1) continue;
PsiParameter[] params = method.getParameterList().getParameters();
if (i >= params.length) continue;
PsiParameter parameter = params[i];
MagicConstantInspection.AllowedValues values =
parameter == null ? null : MagicConstantInspection.getAllowedValues(parameter, parameter.getType(), null);
if (values == null) continue;
if (allowedValues == null) {
allowedValues = values;
continue;
}
if (!allowedValues.equals(values)) return;
}
}
else if (IN_BINARY_COMPARISON.accepts(pos)) {
PsiBinaryExpression exp = PsiTreeUtil.getParentOfType(pos, PsiBinaryExpression.class);
if (exp != null && (exp.getOperationTokenType() == JavaTokenType.EQEQ || exp.getOperationTokenType() == JavaTokenType.NE)) {
PsiExpression l = exp.getLOperand();
PsiElement resolved;
if (l instanceof PsiReferenceExpression && (resolved = ((PsiReferenceExpression)l).resolve()) instanceof PsiModifierListOwner) {
allowedValues = MagicConstantInspection.getAllowedValues((PsiModifierListOwner)resolved, l.getType(), null);
}
PsiExpression r = exp.getROperand();
if (allowedValues == null && r instanceof PsiReferenceExpression && (resolved = ((PsiReferenceExpression)r).resolve()) instanceof PsiModifierListOwner) {
allowedValues = MagicConstantInspection.getAllowedValues((PsiModifierListOwner)resolved, r.getType(), null);
}
}
}
else if (IN_ASSIGNMENT.accepts(pos)) {
PsiAssignmentExpression assignment = PsiTreeUtil.getParentOfType(pos, PsiAssignmentExpression.class);
PsiElement resolved;
PsiExpression l = assignment == null ? null : assignment.getLExpression();
if (assignment != null && PsiTreeUtil.isAncestor(assignment.getRExpression(), pos, false) && l instanceof PsiReferenceExpression && (resolved = ((PsiReferenceExpression)l).resolve()) instanceof PsiModifierListOwner) {
allowedValues = MagicConstantInspection.getAllowedValues((PsiModifierListOwner)resolved, l.getType(), null);
}
}
else if (IN_RETURN.accepts(pos)) {
PsiReturnStatement statement = PsiTreeUtil.getParentOfType(pos, PsiReturnStatement.class);
PsiExpression l = statement == null ? null : statement.getReturnValue();
PsiMethod method = PsiTreeUtil.getParentOfType(l, PsiMethod.class);
if (method != null) {
allowedValues = MagicConstantInspection.getAllowedValues(method, method.getReturnType(), null);
}
}
else if (IN_ANNOTATION_INITIALIZER.accepts(pos)) {
PsiNameValuePair pair = (PsiNameValuePair)pos.getParent().getParent();
PsiAnnotationMemberValue value = pair.getValue();
if (!(value instanceof PsiExpression)) return;
PsiReference ref = pair.getReference();
if (ref == null) return;
PsiMethod method = (PsiMethod)ref.resolve();
if (method == null) return;
allowedValues = MagicConstantInspection.getAllowedValues(method, method.getReturnType(), null);
}
if (allowedValues == null) return;
final Set<PsiElement> allowed = new THashSet<PsiElement>(new TObjectHashingStrategy<PsiElement>() {
@Override
public int computeHashCode(PsiElement object) {
return 0;
}
@Override
public boolean equals(PsiElement o1, PsiElement o2) {
return parameters.getOriginalFile().getManager().areElementsEquivalent(o1, o2);
}
});
if (allowedValues.canBeOred) {
PsiElementFactory factory = JavaPsiFacade.getElementFactory(pos.getProject());
PsiExpression e0 = factory.createExpressionFromText("0", pos);
result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(e0,"0"), PRIORITY-1));
PsiExpression e1 = factory.createExpressionFromText("-1", pos);
result.addElement(PrioritizedLookupElement.withPriority(LookupElementBuilder.create(e1,"-1"), PRIORITY-1));
allowed.add(e0);
allowed.add(e1);
}
for (PsiAnnotationMemberValue value : allowedValues.values) {
if (value instanceof PsiReference) {
PsiElement resolved = ((PsiReference)value).resolve();
if (resolved instanceof PsiNamedElement) {
LookupElement lookupElement = LookupItemUtil.objectToLookupItem(resolved);
if (lookupElement instanceof VariableLookupItem) {
((VariableLookupItem)lookupElement).setSubstitutor(PsiSubstitutor.EMPTY);
}
result.addElement(PrioritizedLookupElement.withPriority(lookupElement, PRIORITY));
allowed.add(resolved);
continue;
}
}
LookupElementBuilder builder = LookupElementBuilder.create(value, value.getText());
result.addElement(builder);
allowed.add(value);
}
result.runRemainingContributors(parameters, new Consumer<CompletionResult>() {
@Override
public void consume(CompletionResult completionResult) {
LookupElement element = completionResult.getLookupElement();
if (allowed.contains(element.getObject())) {
return;
}
result.passResult(completionResult);
}
});
}
}

View File

@@ -0,0 +1,544 @@
/*
* 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.codeInspection.magicConstant;
import com.intellij.analysis.AnalysisScope;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.codeInsight.daemon.GroupNames;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.LocalInspectionToolSession;
import com.intellij.codeInspection.ProblemsHolder;
import com.intellij.ide.util.treeView.AbstractTreeNode;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.javadoc.PsiDocTag;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.LocalSearchScope;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.slicer.*;
import com.intellij.util.Function;
import com.intellij.util.Processor;
import gnu.trove.THashSet;
import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.*;
public class MagicConstantInspection extends LocalInspectionTool {
@Nls
@NotNull
@Override
public String getGroupDisplayName() {
return GroupNames.BUGS_GROUP_NAME;
}
@Nls
@NotNull
@Override
public String getDisplayName() {
return "Magic Constant";
}
@NotNull
@Override
public String getShortName() {
return "MagicConstant";
}
@NotNull
@Override
public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder,
boolean isOnTheFly,
@NotNull LocalInspectionToolSession session) {
return new JavaElementVisitor() {
@Override
public void visitCallExpression(PsiCallExpression callExpression) {
checkCall(callExpression, holder);
}
@Override
public void visitAssignmentExpression(PsiAssignmentExpression expression) {
PsiExpression r = expression.getRExpression();
if (r == null) return;
PsiExpression l = expression.getLExpression();
if (!(l instanceof PsiReferenceExpression)) return;
PsiElement resolved = ((PsiReferenceExpression)l).resolve();
if (!(resolved instanceof PsiModifierListOwner)) return;
PsiModifierListOwner owner = (PsiModifierListOwner)resolved;
PsiType type = expression.getType();
checkExpression(r, owner, type, holder);
}
@Override
public void visitReturnStatement(PsiReturnStatement statement) {
PsiExpression value = statement.getReturnValue();
if (value == null) return;
PsiMethod method = PsiTreeUtil.getParentOfType(statement, PsiMethod.class);
if (method == null) return;
checkExpression(value, method, value.getType(), holder);
}
@Override
public void visitNameValuePair(PsiNameValuePair pair) {
PsiAnnotationMemberValue value = pair.getValue();
if (!(value instanceof PsiExpression)) return;
PsiReference ref = pair.getReference();
if (ref == null) return;
PsiMethod method = (PsiMethod)ref.resolve();
if (method == null) return;
checkExpression((PsiExpression)value, method, method.getReturnType(), holder);
}
@Override
public void visitBinaryExpression(PsiBinaryExpression expression) {
IElementType tokenType = expression.getOperationTokenType();
if (tokenType != JavaTokenType.EQEQ && tokenType != JavaTokenType.NE) return;
PsiExpression l = expression.getLOperand();
PsiExpression r = expression.getROperand();
if (r == null) return;
checkBinary(l, r);
checkBinary(r, l);
}
private void checkBinary(PsiExpression l, PsiExpression r) {
if (l instanceof PsiReference) {
PsiElement resolved = ((PsiReference)l).resolve();
if (resolved instanceof PsiModifierListOwner) {
checkExpression(r, (PsiModifierListOwner)resolved, getType((PsiModifierListOwner)resolved), holder);
}
}
else if (l instanceof PsiMethodCallExpression) {
PsiMethod method = ((PsiMethodCallExpression)l).resolveMethod();
if (method != null) {
checkExpression(r, method, method.getReturnType(), holder);
}
}
}
};
}
private static void checkExpression(PsiExpression expression,
PsiModifierListOwner owner,
PsiType type,
ProblemsHolder holder) {
AllowedValues allowed = getAllowedValues(owner, type, null);
if (allowed == null) return;
PsiElement scope = PsiUtil.getTopLevelEnclosingCodeBlock(expression, null);
if (scope == null) scope = expression;
if (!isAllowed(scope, expression, allowed, expression.getManager())) {
registerProblem(expression, allowed, holder);
}
}
private static void checkCall(@NotNull PsiCallExpression methodCall, @NotNull ProblemsHolder holder) {
PsiMethod method = methodCall.resolveMethod();
if (method == null) return;
PsiParameter[] parameters = method.getParameterList().getParameters();
PsiExpression[] arguments = methodCall.getArgumentList().getExpressions();
for (int i = 0; i < parameters.length; i++) {
PsiParameter parameter = parameters[i];
AllowedValues values = getAllowedValues(parameter, parameter.getType(), null);
if (values == null) continue;
//PsiAnnotation annotation = AnnotationUtil.findAnnotation(parameter, Collections.singletonList(MagicConstant.class.getName()));
//if (annotation == null) continue;
if (i >= arguments.length) break;
PsiExpression argument = arguments[i];
argument = PsiUtil.deparenthesizeExpression(argument);
if (argument == null) continue;
checkMagicParameterArgument(parameter, argument, values, holder);
}
}
static class AllowedValues {
final PsiAnnotationMemberValue[] values;
final boolean canBeOred;
private AllowedValues(PsiAnnotationMemberValue[] values, boolean canBeOred) {
this.values = values;
this.canBeOred = canBeOred;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AllowedValues a2 = (AllowedValues)o;
if (canBeOred != a2.canBeOred) {
return false;
}
Set<PsiAnnotationMemberValue> v1 = new THashSet<PsiAnnotationMemberValue>(Arrays.asList(values));
Set<PsiAnnotationMemberValue> v2 = new THashSet<PsiAnnotationMemberValue>(Arrays.asList(a2.values));
if (v1.size() != v2.size()) {
return false;
}
for (PsiAnnotationMemberValue value : v1) {
for (PsiAnnotationMemberValue value2 : v2) {
if (same(value, value2, value.getManager())) {
v2.remove(value2);
break;
}
}
}
return v2.isEmpty();
}
@Override
public int hashCode() {
int result = values != null ? Arrays.hashCode(values) : 0;
result = 31 * result + (canBeOred ? 1 : 0);
return result;
}
}
private static AllowedValues getAllowedValuesFromMagic(@NotNull PsiModifierListOwner element, @NotNull PsiType type) {
PsiAnnotation magic = AnnotationUtil.findAnnotationInHierarchy(element, Collections.singleton(MagicConstant.class.getName()));
if (magic == null) return null;
PsiAnnotationMemberValue[] allowedValues;
final boolean canBeOred;
if (TypeConversionUtil.getTypeRank(type) <= TypeConversionUtil.LONG_RANK) {
PsiAnnotationMemberValue intValues = magic.findAttributeValue("intValues");
allowedValues = intValues instanceof PsiArrayInitializerMemberValue
? ((PsiArrayInitializerMemberValue)intValues).getInitializers() : PsiAnnotationMemberValue.EMPTY_ARRAY;
if (allowedValues.length == 0) {
PsiAnnotationMemberValue orValue = magic.findAttributeValue("flags");
allowedValues = orValue instanceof PsiArrayInitializerMemberValue ? ((PsiArrayInitializerMemberValue)orValue).getInitializers() : PsiAnnotationMemberValue.EMPTY_ARRAY;
canBeOred = true;
}
else {
canBeOred = false;
}
}
else if (type.equals(PsiType.getJavaLangString(element.getManager(), GlobalSearchScope.allScope(element.getProject())))) {
PsiAnnotationMemberValue strValuesAttr = magic.findAttributeValue("stringValues");
allowedValues = strValuesAttr instanceof PsiArrayInitializerMemberValue ? ((PsiArrayInitializerMemberValue)strValuesAttr).getInitializers() : PsiAnnotationMemberValue.EMPTY_ARRAY;
canBeOred = false;
}
else {
return null; //other types not supported
}
if (allowedValues.length != 0) {
return new AllowedValues(allowedValues, canBeOred);
}
// last resort: try valuesFromClass
PsiAnnotationMemberValue[] values = readFromClass("valuesFromClass", magic, type);
boolean ored = false;
if (values == null) {
values = readFromClass("flagsFromClass", magic, type);
ored = true;
}
if (values == null) return null;
return new AllowedValues(values, ored);
}
private static PsiAnnotationMemberValue[] readFromClass(@NonNls String attributeName, @NotNull PsiAnnotation magic, PsiType type) {
PsiAnnotationMemberValue fromClassAttr = magic.findAttributeValue(attributeName);
PsiType fromClassType = fromClassAttr instanceof PsiClassObjectAccessExpression ? ((PsiClassObjectAccessExpression)fromClassAttr).getOperand().getType() : null;
PsiClass fromClass = fromClassType instanceof PsiClassType ? ((PsiClassType)fromClassType).resolve() : null;
if (fromClass == null) return null;
String fqn = fromClass.getQualifiedName();
if (fqn == null) return null;
List<PsiAnnotationMemberValue> constants = new ArrayList<PsiAnnotationMemberValue>();
for (PsiField field : fromClass.getFields()) {
if (!field.hasModifierProperty(PsiModifier.PUBLIC) || !field.hasModifierProperty(PsiModifier.STATIC) || !field.hasModifierProperty(PsiModifier.FINAL)) continue;
PsiType fieldType = field.getType();
if (!Comparing.equal(fieldType, type)) continue;
PsiAssignmentExpression e = (PsiAssignmentExpression)JavaPsiFacade.getElementFactory(field.getProject()).createExpressionFromText("x="+fqn + "." + field.getName(), field);
PsiReferenceExpression refToField = (PsiReferenceExpression)e.getRExpression();
constants.add(refToField);
}
if (constants.isEmpty()) return null;
return constants.toArray(new PsiAnnotationMemberValue[constants.size()]);
}
static AllowedValues getAllowedValues(@NotNull PsiModifierListOwner element, PsiType type, Set<PsiClass> visited) {
AllowedValues values;
if (type != null) {
values = getAllowedValuesFromMagic(element, type);
if (values != null) return values;
}
PsiAnnotation[] annotations = AnnotationUtil.getAllAnnotations(element, true, null);
for (PsiAnnotation annotation : annotations) {
PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
PsiElement resolved = ref == null ? null : ref.resolve();
if (!(resolved instanceof PsiClass) || !((PsiClass)resolved).isAnnotationType()) continue;
PsiClass aClass = (PsiClass)resolved;
if (visited == null) visited = new THashSet<PsiClass>();
if (!visited.add(aClass)) continue;
values = getAllowedValues(aClass, type, visited);
if (values != null) return values;
}
return parseBeanInfo(element);
}
private static AllowedValues parseBeanInfo(@NotNull PsiModifierListOwner owner) {
PsiMethod method = null;
if (owner instanceof PsiParameter) {
PsiParameter parameter = (PsiParameter)owner;
PsiElement scope = parameter.getDeclarationScope();
if (!(scope instanceof PsiMethod)) return null;
PsiElement nav = scope.getNavigationElement();
if (!(nav instanceof PsiMethod)) return null;
method = (PsiMethod)nav;
if (method.isConstructor()) {
// not a property, try the @ConstructorProperties({"prop"})
PsiAnnotation annotation = AnnotationUtil.findAnnotation(method, "java.beans.ConstructorProperties");
if (annotation == null) return null;
PsiAnnotationMemberValue value = annotation.findAttributeValue("value");
if (!(value instanceof PsiArrayInitializerMemberValue)) return null;
PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers();
PsiElement parent = parameter.getParent();
if (!(parent instanceof PsiParameterList)) return null;
int index = ((PsiParameterList)parent).getParameterIndex(parameter);
if (index >= initializers.length) return null;
PsiAnnotationMemberValue initializer = initializers[index];
if (!(initializer instanceof PsiLiteralExpression)) return null;
Object val = ((PsiLiteralExpression)initializer).getValue();
if (!(val instanceof String)) return null;
PsiMethod setter = PropertyUtil.findPropertySetter(method.getContainingClass(), (String)val, false, false);
if (setter == null) return null;
// try the @beaninfo of the corresponding setter
method = (PsiMethod)setter.getNavigationElement();
}
}
else if (owner instanceof PsiMethod) {
PsiElement nav = owner.getNavigationElement();
if (!(nav instanceof PsiMethod)) return null;
method = (PsiMethod)nav;
}
if (method == null) return null;
PsiClass aClass = method.getContainingClass();
if (aClass == null) return null;
if (PropertyUtil.isSimplePropertyGetter(method)) {
List<PsiMethod> setters = PropertyUtil.getSetters(aClass, PropertyUtil.getPropertyNameByGetter(method));
if (setters.size() != 1) return null;
method = setters.get(0);
}
if (!PropertyUtil.isSimplePropertySetter(method)) return null;
PsiDocComment doc = method.getDocComment();
if (doc == null) return null;
PsiDocTag beaninfo = doc.findTagByName("beaninfo");
if (beaninfo == null) return null;
String data = StringUtil.join(beaninfo.getDataElements(), new Function<PsiElement, String>() {
@Override
public String fun(PsiElement element) {
return element.getText();
}
}, "\n");
int enumIndex = StringUtil.indexOfSubstringEnd(data, "enum:");
if (enumIndex == -1) return null;
data = data.substring(enumIndex);
int colon = data.indexOf(":");
int last = colon == -1 ? data.length() : data.substring(0,colon).lastIndexOf("\n");
data = data.substring(0, last);
List<PsiAnnotationMemberValue> values = new ArrayList<PsiAnnotationMemberValue>();
for (String line : StringUtil.splitByLines(data)) {
List<String> words = StringUtil.split(line, " ", true, true);
if (words.size() != 2) continue;
String ref = words.get(1);
PsiExpression constRef = JavaPsiFacade.getElementFactory(aClass.getProject()).createExpressionFromText(ref, aClass);
if (!(constRef instanceof PsiReferenceExpression)) continue;
PsiReferenceExpression expr = (PsiReferenceExpression)constRef;
values.add(expr);
}
if (values.isEmpty()) return null;
PsiAnnotationMemberValue[] array = values.toArray(new PsiAnnotationMemberValue[values.size()]);
return new AllowedValues(array, false);
}
private static PsiType getType(PsiModifierListOwner element) {
return element instanceof PsiVariable ? ((PsiVariable)element).getType() : element instanceof PsiMethod ? ((PsiMethod)element).getReturnType() : null;
}
private static void checkMagicParameterArgument(@NotNull PsiParameter parameter,
PsiExpression argument,
@NotNull AllowedValues allowedValues,
@NotNull ProblemsHolder holder) {
final PsiManager manager = PsiManager.getInstance(holder.getProject());
if (!argument.getTextRange().isEmpty() && !isAllowed(parameter.getDeclarationScope(), argument, allowedValues, manager)) {
registerProblem(argument, allowedValues, holder);
}
}
private static void registerProblem(PsiExpression argument, AllowedValues allowedValues, ProblemsHolder holder) {
String values = StringUtil.join(allowedValues.values,
new Function<PsiAnnotationMemberValue, String>() {
@Override
public String fun(PsiAnnotationMemberValue value) {
return value.getText();
}
}, ", ");
holder.registerProblem(argument, "Must be one of the: "+ values);
}
private static boolean isAllowed(@NotNull final PsiElement scope,
@NotNull final PsiExpression argument,
@NotNull final AllowedValues allowedValues,
@NotNull final PsiManager manager) {
if (isGoodExpression(argument, allowedValues, scope, manager)) return true;
return processValuesFlownTo(argument, scope, new Processor<PsiExpression>() {
@Override
public boolean process(PsiExpression expression) {
if (false & !PsiTreeUtil.isAncestor(scope, expression, false)) return true;
return isGoodExpression(expression, allowedValues, scope, manager);
}
});
}
private static boolean isGoodExpression(PsiExpression expression,
AllowedValues allowedValues,
PsiElement scope,
PsiManager manager) {
expression = PsiUtil.deparenthesizeExpression(expression);
if (expression == null) return true;
if (expression instanceof PsiConditionalExpression) {
PsiExpression thenExpression = ((PsiConditionalExpression)expression).getThenExpression();
boolean thenAllowed = thenExpression == null || isAllowed(scope, thenExpression, allowedValues, manager);
if (!thenAllowed) return false;
PsiExpression elseExpression = ((PsiConditionalExpression)expression).getElseExpression();
return elseExpression == null || isAllowed(scope, elseExpression, allowedValues, manager);
}
if (isOneOf(expression, allowedValues, manager)) return true;
if (allowedValues.canBeOred) {
if (expression instanceof PsiPolyadicExpression &&
JavaTokenType.OR.equals(((PsiPolyadicExpression)expression).getOperationTokenType())) {
for (PsiExpression operand : ((PsiPolyadicExpression)expression).getOperands()) {
if (!isAllowed(scope, operand, allowedValues, manager)) return false;
}
return true;
}
//todo & ~(CONST | CONST)
PsiExpression zero = JavaPsiFacade.getElementFactory(manager.getProject()).createExpressionFromText("0", expression);
if (same(expression, zero, manager)) return true;
PsiExpression mOne = JavaPsiFacade.getElementFactory(manager.getProject()).createExpressionFromText("-1", expression);
if (same(expression, mOne, manager)) return true;
}
PsiElement resolved = null;
if (expression instanceof PsiReference) {
resolved = ((PsiReference)expression).resolve();
}
else if (expression instanceof PsiCallExpression) {
resolved = ((PsiCallExpression)expression).resolveMethod();
}
AllowedValues allowedForRef;
if (resolved instanceof PsiModifierListOwner &&
(allowedForRef = getAllowedValues((PsiModifierListOwner)resolved, getType((PsiModifierListOwner)resolved), null)) != null &&
Comparing.equal(allowedValues, allowedForRef)) return true;
return PsiType.NULL.equals(expression.getType());
}
private static boolean isOneOf(@NotNull PsiExpression expression, @NotNull AllowedValues allowedValues, @NotNull PsiManager manager) {
for (PsiAnnotationMemberValue allowedValue : allowedValues.values) {
if (same(allowedValue, expression, manager)) return true;
}
return false;
}
private static boolean same(PsiElement e1, PsiElement e2, @NotNull PsiManager manager) {
if (e1 instanceof PsiLiteralExpression && e2 instanceof PsiLiteralExpression) {
return Comparing.equal(((PsiLiteralExpression)e1).getValue(), ((PsiLiteralExpression)e2).getValue());
}
if (e1 instanceof PsiPrefixExpression && e2 instanceof PsiPrefixExpression && ((PsiPrefixExpression)e1).getOperationTokenType() == ((PsiPrefixExpression)e2).getOperationTokenType()) {
return same(((PsiPrefixExpression)e1).getOperand(), ((PsiPrefixExpression)e2).getOperand(), manager);
}
if (e1 instanceof PsiReference && e2 instanceof PsiReference) {
e1 = ((PsiReference)e1).resolve();
e2 = ((PsiReference)e2).resolve();
}
return manager.areElementsEquivalent(e2, e1);
}
private static boolean processValuesFlownTo(@NotNull final PsiExpression argument,
PsiElement scope,
@NotNull final Processor<PsiExpression> processor) {
SliceAnalysisParams params = new SliceAnalysisParams();
params.dataFlowToThis = true;
params.scope = new AnalysisScope(new LocalSearchScope(scope), argument.getProject());
SliceRootNode rootNode = new SliceRootNode(scope.getProject(), new DuplicateMap(), SliceManager.createRootUsage(argument, params));
Collection<? extends AbstractTreeNode> children = rootNode.getChildren().iterator().next().getChildren();
for (AbstractTreeNode child : children) {
SliceUsage usage = (SliceUsage)child.getValue();
PsiElement element = usage.getElement();
if (element instanceof PsiExpression && !processor.process((PsiExpression)element)) return false;
}
return !children.isEmpty();
//Set<PsiElement> elements = new THashSet<PsiElement>(DfaUtil.getPossibleInitializationElements(argument));
//elements.remove(argument);
//if (elements.isEmpty()) return processor.process(argument);
//for (PsiElement element : elements) {
// if (element != argument && !processor.process((PsiExpression)element)) return false;
//}
//return processor.process(argument);
}
}

View File

@@ -44,8 +44,8 @@ import java.util.regex.Pattern;
)
public class SliceManager implements PersistentStateComponent<SliceManager.StoredSettingsBean> {
private final Project myProject;
private final ContentManager myBackContentManager;
private final ContentManager myForthContentManager;
private ContentManager myBackContentManager;
private ContentManager myForthContentManager;
private volatile boolean myCanceled;
private final StoredSettingsBean myStoredSettings = new StoredSettingsBean();
private static final String BACK_TOOLWINDOW_ID = "Analyze Dataflow to";
@@ -60,15 +60,8 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store
return ServiceManager.getService(project, SliceManager.class);
}
public SliceManager(@NotNull Project project, @NotNull ToolWindowManager toolWindowManager, final PsiManager psiManager) {
public SliceManager(@NotNull Project project, PsiManager psiManager) {
myProject = project;
ToolWindow backToolWindow = toolWindowManager.registerToolWindow(BACK_TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, project);
myBackContentManager = backToolWindow.getContentManager();
new ContentManagerWatcher(backToolWindow, myBackContentManager);
ToolWindow forthToolWindow = toolWindowManager.registerToolWindow(FORTH_TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, project);
myForthContentManager = forthToolWindow.getContentManager();
new ContentManagerWatcher(forthToolWindow, myForthContentManager);
psiManager.addPsiTreeChangeListener(new PsiTreeChangeAdapter() {
@Override
@@ -103,6 +96,24 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store
}, project);
}
private ContentManager getContentManager(boolean dataFlowToThis) {
if (dataFlowToThis) {
if (myBackContentManager == null) {
ToolWindow backToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(BACK_TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject);
myBackContentManager = backToolWindow.getContentManager();
new ContentManagerWatcher(backToolWindow, myBackContentManager);
}
return myBackContentManager;
}
if (myForthContentManager == null) {
ToolWindow forthToolWindow = ToolWindowManager.getInstance(myProject).registerToolWindow(FORTH_TOOLWINDOW_ID, true, ToolWindowAnchor.BOTTOM, myProject);
myForthContentManager = forthToolWindow.getContentManager();
new ContentManagerWatcher(forthToolWindow, myForthContentManager);
}
return myForthContentManager;
}
private void cancel() {
myCanceled = true;
}
@@ -121,7 +132,7 @@ public class SliceManager implements PersistentStateComponent<SliceManager.Store
public void createToolWindow(final boolean dataFlowToThis, final SliceRootNode rootNode, boolean splitByLeafExpressions, String displayName) {
final SliceToolwindowSettings sliceToolwindowSettings = SliceToolwindowSettings.getInstance(myProject);
final ContentManager contentManager = dataFlowToThis ? myBackContentManager : myForthContentManager;
final ContentManager contentManager = getContentManager(dataFlowToThis);
final Content[] myContent = new Content[1];
ToolWindow toolWindow = ToolWindowManager.getInstance(myProject).getToolWindow(dataFlowToThis ? BACK_TOOLWINDOW_ID : FORTH_TOOLWINDOW_ID);
final SlicePanel slicePanel = new SlicePanel(myProject, dataFlowToThis, rootNode, splitByLeafExpressions, toolWindow) {

View File

@@ -57,7 +57,7 @@ public class TypeConversionUtil {
public static final int SHORT_RANK = 2;
public static final int CHAR_RANK = 3;
public static final int INT_RANK = 4;
private static final int LONG_RANK = 5;
public static final int LONG_RANK = 5;
private static final int FLOAT_RANK = 6;
private static final int DOUBLE_RANK = 7;
private static final int BOOL_RANK = 10;
@@ -540,18 +540,16 @@ public class TypeConversionUtil {
if (i == JavaTokenType.MINUSMINUS || i == JavaTokenType.PLUSPLUS) {
return typeRank <= MAX_NUMERIC_RANK;
}
else if (i == JavaTokenType.MINUS || i == JavaTokenType.PLUS) {
if (i == JavaTokenType.MINUS || i == JavaTokenType.PLUS) {
return typeRank <= MAX_NUMERIC_RANK;
}
else if (i == JavaTokenType.TILDE) {
if (i == JavaTokenType.TILDE) {
return typeRank <= LONG_RANK;
}
else if (i == JavaTokenType.EXCL) {
if (i == JavaTokenType.EXCL) {
return typeRank == BOOL_RANK;
}
else {
LOG.error("unknown token: " + token);
}
LOG.error("unknown token: " + token);
return true;
}

View File

@@ -0,0 +1,435 @@
<?xml version="1.0" encoding="UTF-8"?>
<problems>
<!--<problem>-->
<!--<file>X.java</file>-->
<!--<line>5</line>-->
<!--<problem_class>Duplicate throws</problem_class>-->
<!--<description>Duplicate throws</description>-->
<!--</problem>-->
<problem>
<file>X.java</file>
<line>29</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>30</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>31</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>33</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>34</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>35</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>36</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>55</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>56</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>57</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>59</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>60</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>61</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>62</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>81</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>82</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>83</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>85</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>86</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>87</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>88</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>118</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>119</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>122</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>123</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>124</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>125</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>173</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>174</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>175</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>177</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>178</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>179</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>180</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y, Const.Z</description>
</problem>
<problem>
<file>X.java</file>
<line>193</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
<problem>
<file>X.java</file>
<line>195</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
<problem>
<file>X.java</file>
<line>227</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
<problem>
<file>X.java</file>
<line>228</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
<problem>
<file>X.java</file>
<line>229</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
<problem>
<file>X.java</file>
<line>230</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
<problem>
<file>X.java</file>
<line>231</line>
<problem_class severity="WARNING" attribute_key="WARNING_ATTRIBUTES">magic constant</problem_class>
<description>Must be one of the: Const.X, Const.Y</description>
</problem>
</problems>

View File

@@ -0,0 +1,235 @@
/*
* 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.
*/
import org.intellij.lang.annotations.MagicConstant;
import java.io.*;
class Const {
public static final int X = 0;
public static final int Y = 2;
public static final int Z = 3;
}
public class X {
void f(@MagicConstant(intValues={Const.X, Const.Y, Const.Z}) int x) {
/////////// BAD
f(0);
f(1);
f(Const.X | Const.Y);
int i = Const.X | Const.Y;
f(i);
if (x == 3) {
x = 2;
assert x != 1;
}
////////////// GOOD
f(Const.X);
f(Const.Y);
f(Const.Z);
int i2 = this == null ? Const.X : Const.Y;
f(i2);
if (x == Const.X) {
x = Const.Y;
assert x != Const.Z;
}
f2(x);
}
void f2(@MagicConstant(valuesFromClass =Const.class) int x) {
/////////// BAD
f2(0);
f2(1);
f2(Const.X | Const.Y);
int i = Const.X | Const.Y;
f2(i);
if (x == 3) {
x = 2;
assert x != 1;
}
////////////// GOOD
f2(Const.X);
f2(Const.Y);
f2(Const.Z);
int i2 = this == null ? Const.X : Const.Y;
f2(i2);
if (x == Const.X) {
x = Const.Y;
assert x != Const.Z;
}
f(x);
}
void f3(@MagicConstant(flags ={Const.X, Const.Y, Const.Z}) int x) {
/////////// BAD
f3(2);
f3(1);
f(Const.X | Const.Y);
int i = Const.X | 4;
f3(i);
if (x == 3) {
x = 2;
assert x != 1;
}
////////////// GOOD
f3(Const.X);
f3(Const.Y);
f3(Const.Z);
int i2 = this == null ? Const.X : Const.Y;
f3(i2);
int ix = Const.X | Const.Y;
f3(ix);
f3(0);
f3(-1);
int f = 0;
if (x == Const.X) {
x = Const.Y;
assert x != Const.Z;
f |= Const.Y;
}
else {
f |= Const.X;
}
f3(f);
f4(x);
}
void f4(@MagicConstant(flagsFromClass =Const.class) int x) {
/////////// BAD
f4(-3);
f4(1);
f4(Const.X | Const.Y);
int i = Const.X | 4;
f4(i);
if (x == 3) {
x = 2;
assert x != 1;
}
////////////// GOOD
f4(Const.X);
f4(Const.Y);
f4(Const.Z);
int i2 = this == null ? Const.X : Const.Y;
f4(i2);
int ix = Const.X | Const.Y;
f4(ix);
f4(0);
f4(-1);
int f = 0;
if (x == Const.X) {
x = Const.Y;
assert x != Const.Z;
f |= Const.Y;
}
else {
f |= Const.X;
}
f4(f);
f3(x);
}
class Alias {
@MagicConstant(intValues={Const.X, Const.Y, Const.Z})
@interface IntEnum{}
void f(@IntEnum int x) {
////////////// GOOD
f(Const.X);
f(Const.Y);
f(Const.Z);
int i2 = this == null ? Const.X : Const.Y;
f(i2);
if (x == Const.X) {
x = Const.Y;
assert x != Const.Z;
}
f2(x);
/////////// BAD
f(0);
f(1);
f(Const.X | Const.Y);
int i = Const.X | Const.Y;
f(i);
if (x == 3 || getClass().isInterface()) {
x = 2;
assert x != 1;
}
f2(x);
}
}
class MagicAnnoInsideAnnotationUsage {
@interface III {
@MagicConstant(intValues = {Const.X, Const.Y}) int val();
}
// bad
@III(val = 2)
int h;
@III(val = Const.X | Const.Y)
void f(){}
// good
@III(val = Const.X)
int h2;
}
abstract class BeanInfoParsing {
/**
* @see java.lang.Runtime#exit(int)
*
* @beaninfo
* preferred: true
* bound: true
* enum: DO_NOTHING_ON_CLOSE Const.X
* HIDE_ON_CLOSE Const.Y
* description: The frame's default close operation.
*/
public void setX(int operation) {
}
public abstract int getX();
{
// good
setX(Const.X);
setX(Const.Y);
if (getX() == Const.X || getX() == Const.Y) {}
// bad
setX(0);
setX(-1);
setX(Const.Z);
if (getX() == 1) {}
if (getX() == Const.Z) {}
}
}
}

View File

@@ -0,0 +1,75 @@
/*
* 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.
*/
/*
* Created by IntelliJ IDEA.
* User: max
* Date: Apr 11, 2002
* Time: 6:50:50 PM
* To change template for new class use
* Code Style | Class Templates options (Tools | IDE Options).
*/
package com.intellij.codeInspection;
import com.intellij.JavaTestUtil;
import com.intellij.codeInspection.ex.LocalInspectionToolWrapper;
import com.intellij.codeInspection.magicConstant.MagicConstantInspection;
import com.intellij.testFramework.InspectionTestCase;
public class MagicConstantInspectionTest extends InspectionTestCase {
@Override
protected String getTestDataPath() {
return JavaTestUtil.getJavaTestDataPath() + "/inspection";
}
private void doTest() throws Exception {
doTest("magic/" + getTestName(true), new LocalInspectionToolWrapper(new MagicConstantInspection()), "jdk 1.7");
}
public void testSimple() throws Exception { doTest(); }
//{
// SecurityManager securityManager = System.getSecurityManager();
// securityManager.checkMemberAccess(getClass(), 948);
//
// Font font = null;
// new Cursor() ;
// JOptionPane.showConfirmDialog(null, null, null, 0, );
// JList l = null;
// l.getSelectionModel().setSelectionMode();
// new JSplitPane(9);
// MouseWheelEvent event = new MouseWheelEvent(null,0,0,0,0,0,0,false,0,0,0 );
// Pattern p = Pattern.compile("", Pattern.CANON_EQ);
// JTree t = null; t.getSelectionModel().setSelectionMode();
//
// TitledBorder border = new TitledBorder(null,"",0,0);
// new JLabel("text", )
// Calendar calendar = Calendar.getInstance();
// new Font("Arial", )
//}
//public static Font createFont() {
// return new Font("Arial", );
//}
}

View File

@@ -87,7 +87,7 @@ public class AnnotationUtil {
}
@Nullable
public static PsiAnnotation findAnnotation(PsiModifierListOwner listOwner, @NotNull Set<String> annotationNames) {
public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, @NotNull Set<String> annotationNames) {
return findAnnotation(listOwner, (Collection<String>)annotationNames);
}
@@ -97,7 +97,7 @@ public class AnnotationUtil {
}
@Nullable
public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, Collection<String> annotationNames,
public static PsiAnnotation findAnnotation(@Nullable PsiModifierListOwner listOwner, @NotNull Collection<String> annotationNames,
final boolean skipExternal) {
if (listOwner == null) return null;
final PsiModifierList list = listOwner.getModifierList();
@@ -138,7 +138,7 @@ public class AnnotationUtil {
}
@Nullable
public static PsiAnnotation findAnnotationInHierarchy(PsiModifierListOwner listOwner, Set<String> annotationNames) {
public static PsiAnnotation findAnnotationInHierarchy(PsiModifierListOwner listOwner, @NotNull Set<String> annotationNames) {
PsiAnnotation directAnnotation = findAnnotation(listOwner, annotationNames);
if (directAnnotation != null) return directAnnotation;
if (listOwner instanceof PsiMethod) {
@@ -146,15 +146,17 @@ public class AnnotationUtil {
PsiClass aClass = method.getContainingClass();
if (aClass == null) return null;
HierarchicalMethodSignature methodSignature = method.getHierarchicalMethodSignature();
return findAnnotationInHierarchy(methodSignature, annotationNames, method, null);
} else if (listOwner instanceof PsiClass) {
return findAnnotationInHierarchy(((PsiClass)listOwner), annotationNames, null);
return findAnnotationInHierarchy(methodSignature, annotationNames, method, null,
JavaPsiFacade.getInstance(method.getProject()).getResolveHelper());
}
if (listOwner instanceof PsiClass) {
return findAnnotationInHierarchy((PsiClass)listOwner, annotationNames, null);
}
return null;
}
@Nullable
private static PsiAnnotation findAnnotationInHierarchy(final @NotNull PsiClass psiClass, final Set<String> annotationNames, @Nullable Set<PsiClass> processed) {
private static PsiAnnotation findAnnotationInHierarchy(@NotNull final PsiClass psiClass, final Set<String> annotationNames, @Nullable Set<PsiClass> processed) {
final PsiClass[] superClasses = psiClass.getSupers();
for (final PsiClass superClass : superClasses) {
if (processed == null) processed = new THashSet<PsiClass>();
@@ -168,12 +170,12 @@ public class AnnotationUtil {
}
@Nullable
private static PsiAnnotation findAnnotationInHierarchy(HierarchicalMethodSignature signature,
Set<String> annotationNames,
PsiElement place,
@Nullable Set<PsiMethod> processed) {
private static PsiAnnotation findAnnotationInHierarchy(@NotNull HierarchicalMethodSignature signature,
@NotNull Set<String> annotationNames,
@NotNull PsiElement place,
@Nullable Set<PsiMethod> processed,
@NotNull PsiResolveHelper resolveHelper) {
final List<HierarchicalMethodSignature> superSignatures = signature.getSuperSignatures();
final PsiResolveHelper resolveHelper = JavaPsiFacade.getInstance(place.getProject()).getResolveHelper();
for (final HierarchicalMethodSignature superSignature : superSignatures) {
final PsiMethod superMethod = superSignature.getMethod();
if (processed == null) processed = new THashSet<PsiMethod>();
@@ -181,7 +183,7 @@ public class AnnotationUtil {
if (!resolveHelper.isAccessible(superMethod, place, null)) continue;
PsiAnnotation direct = findAnnotation(superMethod, annotationNames);
if (direct != null) return direct;
PsiAnnotation superResult = findAnnotationInHierarchy(superSignature, annotationNames, place, processed);
PsiAnnotation superResult = findAnnotationInHierarchy(superSignature, annotationNames, place, processed, resolveHelper);
if (superResult != null) return superResult;
}
@@ -261,10 +263,10 @@ public class AnnotationUtil {
* @return <code>true</code> if annotated of at least one annotation from the annotations list
*/
public static boolean checkAnnotatedUsingPatterns(PsiModifierListOwner owner, Collection<String> annotations) {
List<String> fqns = null;
final PsiModifierList modList;
if (owner == null || (modList = owner.getModifierList()) == null) return false;
List<String> fqns = null;
for (String fqn : annotations) {
boolean isPattern = fqn.endsWith("*");
if (!isPattern && isAnnotated(owner, fqn, false)) {
@@ -307,4 +309,71 @@ public class AnnotationUtil {
}
return null;
}
@NotNull
public static PsiAnnotation[] getAllAnnotations(@NotNull PsiModifierListOwner owner, boolean inHierarchy, Set<PsiModifierListOwner> visited) {
final PsiModifierList list = owner.getModifierList();
PsiAnnotation[] annotations = PsiAnnotation.EMPTY_ARRAY;
if (list != null) {
annotations = list.getAnnotations();
}
final PsiAnnotation[] externalAnnotations = ExternalAnnotationsManager.getInstance(owner.getProject()).findExternalAnnotations(owner);
if (externalAnnotations != null) {
annotations = ArrayUtil.mergeArrays(annotations, externalAnnotations, PsiAnnotation.ARRAY_FACTORY);
}
if (inHierarchy) {
if (owner instanceof PsiClass) {
for (PsiClass superClass : ((PsiClass)owner).getSupers()) {
if (visited == null) visited = new THashSet<PsiModifierListOwner>();
if (visited.add(superClass)) annotations = ArrayUtil.mergeArrays(annotations, getAllAnnotations(superClass, inHierarchy, visited));
}
}
else if (owner instanceof PsiMethod) {
PsiMethod method = (PsiMethod)owner;
PsiClass aClass = method.getContainingClass();
if (aClass != null) {
HierarchicalMethodSignature methodSignature = method.getHierarchicalMethodSignature();
final List<HierarchicalMethodSignature> superSignatures = methodSignature.getSuperSignatures();
PsiResolveHelper resolveHelper = PsiResolveHelper.SERVICE.getInstance(aClass.getProject());
for (final HierarchicalMethodSignature superSignature : superSignatures) {
final PsiMethod superMethod = superSignature.getMethod();
if (visited == null) visited = new THashSet<PsiModifierListOwner>();
if (!visited.add(superMethod)) continue;
if (!resolveHelper.isAccessible(superMethod, owner, null)) continue;
annotations = ArrayUtil.mergeArrays(annotations, getAllAnnotations(superMethod, inHierarchy, visited));
}
}
}
else if (owner instanceof PsiParameter) {
PsiParameter parameter = (PsiParameter)owner;
PsiElement scope = parameter.getDeclarationScope();
if (scope instanceof PsiMethod) {
PsiMethod method = (PsiMethod)scope;
PsiClass aClass = method.getContainingClass();
PsiElement parent = parameter.getParent();
if (aClass != null && parent instanceof PsiParameterList) {
int index = ((PsiParameterList)parent).getParameterIndex(parameter);
HierarchicalMethodSignature methodSignature = method.getHierarchicalMethodSignature();
final List<HierarchicalMethodSignature> superSignatures = methodSignature.getSuperSignatures();
PsiResolveHelper resolveHelper = PsiResolveHelper.SERVICE.getInstance(aClass.getProject());
for (final HierarchicalMethodSignature superSignature : superSignatures) {
final PsiMethod superMethod = superSignature.getMethod();
if (visited == null) visited = new THashSet<PsiModifierListOwner>();
if (!visited.add(superMethod)) continue;
if (!resolveHelper.isAccessible(superMethod, owner, null)) continue;
PsiParameter[] superParameters = superMethod.getParameterList().getParameters();
if (index < superParameters.length) {
annotations = ArrayUtil.mergeArrays(annotations, getAllAnnotations(superParameters[index], inHierarchy, visited));
}
}
}
}
}
}
return annotations;
}
}

View File

@@ -17,18 +17,24 @@ package com.intellij.psi.util;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import org.intellij.lang.annotations.MagicConstant;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class PsiFormatUtil extends PsiFormatUtilBase {
@MagicConstant(flags = {SHOW_MODIFIERS, SHOW_TYPE, TYPE_AFTER, SHOW_CONTAINING_CLASS, SHOW_FQ_NAME, SHOW_NAME, SHOW_MODIFIERS, SHOW_INITIALIZER, SHOW_RAW_TYPE, SHOW_RAW_NON_TOP_TYPE, SHOW_FQ_CLASS_NAMES})
public @interface FormatVariableOptions {}
public static String formatVariable(PsiVariable variable, int options, PsiSubstitutor substitutor){
public static String formatVariable(PsiVariable variable, @FormatVariableOptions int options, PsiSubstitutor substitutor){
StringBuilder buffer = new StringBuilder();
formatVariable(variable, options, substitutor,buffer);
return buffer.toString();
}
private static void formatVariable(PsiVariable variable, int options, PsiSubstitutor substitutor,StringBuilder buffer){
private static void formatVariable(PsiVariable variable,
@FormatVariableOptions int options,
PsiSubstitutor substitutor,
@NotNull StringBuilder buffer){
if ((options & SHOW_MODIFIERS) != 0 && (options & MODIFIERS_AFTER) == 0){
formatModifiers(variable, options,buffer);
}
@@ -97,16 +103,20 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
}
}
public static String formatMethod(PsiMethod method, PsiSubstitutor substitutor, int options, int parameterOptions){
public static String formatMethod(PsiMethod method, PsiSubstitutor substitutor, @FormatMethodOptions int options, @FormatVariableOptions int parameterOptions){
return formatMethod(method, substitutor, options, parameterOptions, MAX_PARAMS_TO_SHOW);
}
public static String formatMethod(PsiMethod method, PsiSubstitutor substitutor, int options, int parameterOptions, int maxParametersToShow){
public static String formatMethod(PsiMethod method, PsiSubstitutor substitutor, @FormatMethodOptions int options, @FormatVariableOptions int parameterOptions, int maxParametersToShow){
StringBuilder buffer = new StringBuilder();
formatMethod(method, substitutor, options, parameterOptions, maxParametersToShow,buffer);
return buffer.toString();
}
private static void formatMethod(PsiMethod method, PsiSubstitutor substitutor, int options, int parameterOptions, int maxParametersToShow, StringBuilder buffer){
@MagicConstant(flags = {SHOW_MODIFIERS, MODIFIERS_AFTER, SHOW_TYPE, TYPE_AFTER, SHOW_CONTAINING_CLASS, SHOW_FQ_NAME, SHOW_NAME, SHOW_PARAMETERS, SHOW_THROWS, SHOW_RAW_TYPE, SHOW_RAW_NON_TOP_TYPE, SHOW_FQ_CLASS_NAMES})
public @interface FormatMethodOptions {}
private static void formatMethod(PsiMethod method, PsiSubstitutor substitutor, @FormatMethodOptions int options, @FormatVariableOptions int parameterOptions, int maxParametersToShow, StringBuilder buffer){
if ((options & SHOW_MODIFIERS) != 0 && (options & MODIFIERS_AFTER) == 0){
formatModifiers(method, options,buffer);
}
@@ -177,7 +187,7 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
}
if ((options & SHOW_THROWS) != 0){
String throwsText = formatReferenceList(method.getThrowsList(), options);
if (throwsText.length() > 0){
if (!throwsText.isEmpty()){
appendSpaceIfNeeded(buffer);
//noinspection HardCodedStringLiteral
buffer.append("throws ");
@@ -186,7 +196,12 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
}
}
@NotNull public static String formatClass(@NotNull PsiClass aClass, int options){
@MagicConstant(flags = {SHOW_MODIFIERS, SHOW_NAME, SHOW_ANONYMOUS_CLASS_VERBOSE, SHOW_FQ_NAME, MODIFIERS_AFTER, SHOW_EXTENDS_IMPLEMENTS, SHOW_REDUNDANT_MODIFIERS, JAVADOC_MODIFIERS_ONLY})
public @interface FormatClassOptions {}
@NotNull
public static String formatClass(@NotNull PsiClass aClass, @FormatClassOptions int options){
StringBuilder buffer = new StringBuilder();
if ((options & SHOW_MODIFIERS) != 0 && (options & MODIFIERS_AFTER) == 0){
formatModifiers(aClass, options,buffer);
@@ -222,14 +237,14 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
}
if ((options & SHOW_EXTENDS_IMPLEMENTS) != 0){
String extendsText = formatReferenceList(aClass.getExtendsList(), options);
if (extendsText.length() > 0){
if (!extendsText.isEmpty()){
appendSpaceIfNeeded(buffer);
//noinspection HardCodedStringLiteral
buffer.append("extends ");
buffer.append(extendsText);
}
String implementsText = formatReferenceList(aClass.getImplementsList(), options);
if (implementsText.length() > 0){
if (!implementsText.isEmpty()){
appendSpaceIfNeeded(buffer);
//noinspection HardCodedStringLiteral
buffer.append("implements ");
@@ -340,7 +355,7 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
return buffer.toString();
}
public static String formatType(PsiType type, int options, PsiSubstitutor substitutor){
public static String formatType(PsiType type, int options, @NotNull PsiSubstitutor substitutor){
type = substitutor.substitute(type);
if ((options & SHOW_RAW_TYPE) != 0) {
type = TypeConversionUtil.erasure(type);
@@ -367,6 +382,11 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
@Nullable
public static String getExternalName(PsiModifierListOwner owner, final boolean showParamName) {
return getExternalName(owner, showParamName, MAX_PARAMS_TO_SHOW);
}
@Nullable
public static String getExternalName(PsiModifierListOwner owner, final boolean showParamName, int maxParamsToShow) {
final StringBuilder builder = new StringBuilder();
if (owner instanceof PsiClass) {
ClassUtil.formatClassName((PsiClass)owner, builder);
@@ -379,7 +399,7 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
builder.append(" ");
formatMethod((PsiMethod)owner, PsiSubstitutor.EMPTY,
SHOW_NAME | SHOW_FQ_NAME | SHOW_TYPE | SHOW_PARAMETERS | SHOW_FQ_CLASS_NAMES,
showParamName ? SHOW_NAME | SHOW_TYPE | SHOW_FQ_CLASS_NAMES : SHOW_TYPE | SHOW_FQ_CLASS_NAMES, MAX_PARAMS_TO_SHOW, builder);
showParamName ? SHOW_NAME | SHOW_TYPE | SHOW_FQ_CLASS_NAMES : SHOW_TYPE | SHOW_FQ_CLASS_NAMES, maxParamsToShow, builder);
}
else if (owner instanceof PsiField) {
builder.append(" ").append(((PsiField)owner).getName());
@@ -392,7 +412,7 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
builder.append(" ");
formatMethod(psiMethod, PsiSubstitutor.EMPTY,
SHOW_NAME | SHOW_FQ_NAME | SHOW_TYPE | SHOW_PARAMETERS | SHOW_FQ_CLASS_NAMES,
showParamName ? SHOW_NAME | SHOW_TYPE | SHOW_FQ_CLASS_NAMES : SHOW_TYPE | SHOW_FQ_CLASS_NAMES, MAX_PARAMS_TO_SHOW, builder);
showParamName ? SHOW_NAME | SHOW_TYPE | SHOW_FQ_CLASS_NAMES : SHOW_TYPE | SHOW_FQ_CLASS_NAMES, maxParamsToShow, builder);
builder.append(" ");
if (showParamName) {
@@ -415,7 +435,7 @@ public class PsiFormatUtil extends PsiFormatUtilBase {
public static String getPackageDisplayName(@NotNull final PsiClass psiClass) {
@NonNls String packageName = psiClass.getQualifiedName();
packageName = packageName == null || packageName.lastIndexOf('.') <= 0 ? "" : packageName.substring(0, packageName.lastIndexOf('.'));
if (packageName.length() == 0) {
if (packageName.isEmpty()) {
packageName = "default package";
}
return packageName;

View File

@@ -0,0 +1,32 @@
/*
* 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.intellij.lang.annotations;
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE,
ElementType.ANNOTATION_TYPE, // to subclass
ElementType.METHOD
})
public @interface MagicConstant {
Class valuesFromClass() default void.class;
Class flagsFromClass() default void.class; // int constants which can be combined via | (bitwise or) operator. 0 and -1 are considered acceptable values.
String[] stringValues() default {};
long[] intValues() default {};
long[] flags() default {}; // int constants which can be combined via | (bitwise or) operator. 0 and -1 are considered acceptable values.
}

View File

@@ -443,6 +443,7 @@
<completion.skip implementation="com.intellij.codeInsight.template.impl.LiveTemplateCompletionContributor$Skipper" id="skipLiveTemplate"/>
<completion.contributor language="TEXT" implementationClass="com.intellij.openapi.vcs.CommitCompletionContributor" id="commitCompletion" order="first, before liveTemplates"/>
<completion.contributor language="JAVA" implementationClass="com.intellij.codeInspection.magicConstant.MagicCompletionContributor" id="magicCompletion" order="first, before liveTemplates"/>
<applicationService serviceInterface="com.intellij.execution.console.ConsoleFoldingSettings" serviceImplementation="com.intellij.execution.console.ConsoleFoldingSettings"/>
<console.folding implementation="com.intellij.execution.console.SubstringConsoleFolding"/>

View File

@@ -0,0 +1,13 @@
<html>
<body>
<font face="verdana" size="-1">Report occurrences where usages of "magic" constants only are allowed
but other expressions are used instead.<br>
E.g. <b><font color="#000080">new </font></b> Font("Arial", <b><font color="#000080">42</font></b>) <br>
instead of <b><font color="#000080">new </font></b> Font("Arial", Font.<b><font color="#000080">BOLD</font></b>) <br>
<br><br>
Please see <code>org.intellij.lang.annotations.MagicConstant</code> annotation description for details.
</font>
</body>
</html>

View File

@@ -515,6 +515,9 @@
<localInspection language="JAVA" shortName="JavacQuirks" bundle="messages.InspectionsBundle" key="inspection.compiler.javac.quirks.name"
groupName="Compiler issues" enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.codeInspection.compiler.JavacQuirksInspection" />
<localInspection language="JAVA" shortName="MagicConstant" displayName="Magic Constant"
groupName="Probable bugs" enabledByDefault="true" level="WARNING"
implementationClass="com.intellij.codeInspection.magicConstant.MagicConstantInspection" />
<intentionAction>
<className>com.intellij.codeInsight.intention.impl.SplitIfAction</className>