/*
* 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.codeInsight;
import com.intellij.openapi.components.*;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.DefaultJDOMExternalizer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.JDOMExternalizableStringList;
import com.intellij.openapi.util.WriteExternalException;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiModifierListOwner;
import org.jdom.Element;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* User: anna
* Date: 1/25/11
*/
public class NullableNotNullManager implements PersistentStateComponent<Element> {
private static final Logger LOG = Logger.getInstance("#" + NullableNotNullManager.class.getName());
public String myDefaultNullable = AnnotationUtil.NULLABLE;
public String myDefaultNotNull = AnnotationUtil.NOT_NULL;
public final JDOMExternalizableStringList myNullables = new JDOMExternalizableStringList();
public final JDOMExternalizableStringList myNotNulls = new JDOMExternalizableStringList();
public static final String[] DEFAULT_NULLABLES = {AnnotationUtil.NULLABLE, "javax.annotation.Nullable", "edu.umd.cs.findbugs.annotations.Nullable"};
public static final String[] DEFAULT_NOT_NULLS = {AnnotationUtil.NOT_NULL, "javax.annotation.Nonnull", "edu.umd.cs.findbugs.annotations.NonNull"};
public NullableNotNullManager() {
Collections.addAll(myNotNulls, DEFAULT_NOT_NULLS);
Collections.addAll(myNullables, DEFAULT_NULLABLES);
}
public static NullableNotNullManager getInstance(Project project) {
return ServiceManager.getService(project, NullableNotNullManager.class);
}
public Collection<String> getAllAnnotations() {
final List<String> all = new ArrayList<String>(getNullables());
all.addAll(getNotNulls());
return all;
}
private static void addAllIfNotPresent(Collection<String> collection, String... annotations) {
for (String annotation : annotations) {
LOG.assertTrue(annotation != null);
if (!collection.contains(annotation)) {
collection.add(annotation);
}
}
}
public void setNotNulls(String... annotations) {
myNotNulls.clear();
addAllIfNotPresent(myNotNulls, DEFAULT_NOT_NULLS);
addAllIfNotPresent(myNotNulls, annotations);
}
public void setNullables(String... annotations) {
myNullables.clear();
addAllIfNotPresent(myNullables, DEFAULT_NULLABLES);
addAllIfNotPresent(myNullables, annotations);
}
public String getDefaultNullable() {
return myDefaultNullable;
}
public String getPresentableDefaultNullable() {
return StringUtil.getShortName(myDefaultNullable);
}
@Nullable
public String getNullable(PsiModifierListOwner owner) {
for (String nullable : getNullables()) {
if (AnnotationUtil.isAnnotated(owner, nullable, false, false)) return nullable;
}
return null;
}
public void setDefaultNullable(@NotNull String defaultNullable) {
LOG.assertTrue(getNullables().contains(defaultNullable));
myDefaultNullable = defaultNullable;
}
public String getDefaultNotNull() {
return myDefaultNotNull;
}
public String getPresentableDefaultNotNull() {
return StringUtil.getShortName(myDefaultNotNull);
}
@Nullable
public String getNotNull(PsiModifierListOwner owner) {
for (String notNull : getNotNulls()) {
if (AnnotationUtil.isAnnotated(owner, notNull, false, false)) return notNull;
}
return null;
}
public void setDefaultNotNull(@NotNull String defaultNotNull) {
LOG.assertTrue(getNotNulls().contains(defaultNotNull));
myDefaultNotNull = defaultNotNull;
}
public boolean isNullable(PsiModifierListOwner owner, boolean checkBases) {
return AnnotationUtil.isAnnotated(owner, getNullables(), checkBases, false);
}
public boolean isNotNull(PsiModifierListOwner owner, boolean checkBases) {
return AnnotationUtil.isAnnotated(owner, getNotNulls(), checkBases, false);
}
public List<String> getNullables() {
return myNullables;
}
public List<String> getNotNulls() {
return myNotNulls;
}
public boolean hasDefaultValues() {
if (DEFAULT_NULLABLES.length != getNullables().size() || DEFAULT_NOT_NULLS.length != getNotNulls().size()) {
return false;
}
if (!myDefaultNotNull.equals(AnnotationUtil.NOT_NULL) || !myDefaultNullable.equals(AnnotationUtil.NULLABLE)) {
return false;
}
for (int i = 0; i < DEFAULT_NULLABLES.length; i++) {
if (!getNullables().get(i).equals(DEFAULT_NULLABLES[i])) {
return false;
}
}
for (int i = 0; i < DEFAULT_NOT_NULLS.length; i++) {
if (!getNotNulls().get(i).equals(DEFAULT_NOT_NULLS[i])) {
return false;
}
}
return true;
}
@Override
public Element getState() {
final Element component = new Element("component");
if (hasDefaultValues()) {
return component;
}
try {
DefaultJDOMExternalizer.writeExternal(this, component);
}
catch (WriteExternalException e) {
LOG.error(e);
}
return component;
}
@Override
public void loadState(Element state) {
try {
DefaultJDOMExternalizer.readExternal(this, state);
if (myNullables.isEmpty()) {
Collections.addAll(myNullables, DEFAULT_NULLABLES);
}
if (myNotNulls.isEmpty()) {
Collections.addAll(myNotNulls, DEFAULT_NOT_NULLS);
}
}
catch (InvalidDataException e) {
LOG.error(e);
}
}
public static boolean isNullable(@NotNull PsiModifierListOwner owner) {
return !isNotNull(owner) && getInstance(owner.getProject()).isNullable(owner, true);
}
public static boolean isNotNull(@NotNull PsiModifierListOwner owner) {
return getInstance(owner.getProject()).isNotNull(owner, true);
}
}