/*
* Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.google.errorprone;
import static com.google.common.base.Verify.verifyNotNull;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.FluentIterable;
import com.google.errorprone.BugPattern.SeverityLevel;
import com.google.errorprone.BugPattern.Suppressibility;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.AnnotationValue;
import javax.lang.model.element.Element;
import javax.lang.model.element.ExecutableElement;
/** A serialization-friendly POJO of the information in a {@link BugPattern}. */
public final class BugPatternInstance {
private static final Function<AnnotationValue, String> TO_STRING =
new Function<AnnotationValue, String>() {
@Override
public String apply(AnnotationValue input) {
return input.toString();
}
};
public String className;
public String name;
public String summary;
public String explanation;
public String[] altNames;
public String category;
public SeverityLevel severity;
public Suppressibility suppressibility;
public String[] customSuppressionAnnotations;
public boolean documentSuppression = true;
public boolean generateExamplesFromTestCases = true;
public static BugPatternInstance fromElement(Element element) {
BugPatternInstance instance = new BugPatternInstance();
instance.className = element.toString();
BugPattern annotation = element.getAnnotation(BugPattern.class);
instance.name = annotation.name();
instance.altNames = annotation.altNames();
instance.severity = annotation.severity();
instance.suppressibility = annotation.suppressibility();
instance.summary = annotation.summary();
instance.explanation = annotation.explanation();
instance.documentSuppression = annotation.documentSuppression();
Map<String, Object> keyValues = getAnnotation(element, BugPattern.class.getName());
instance.category = verifyNotNull(keyValues.get("category")).toString();
Object result = keyValues.get("customSuppressionAnnotations");
if (result == null) {
instance.customSuppressionAnnotations = new String[0];
} else {
Preconditions.checkState(result instanceof List);
// The doc for AnnotationValue says that if the value is an array, then
// AnnotationValue#getValue() will return a List<? extends AnnotationValue>.
@SuppressWarnings("unchecked")
List<? extends AnnotationValue> resultList = (List<? extends AnnotationValue>) result;
instance.customSuppressionAnnotations =
FluentIterable.from(resultList)
.transform(TO_STRING)
.toArray(String.class);
}
instance.generateExamplesFromTestCases =
!keyValues.containsKey("generateExamplesFromTestCases")
|| (boolean) keyValues.get("generateExamplesFromTestCases");
return instance;
}
private static Map<String, Object> getAnnotation(Element element, String name) {
for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
if (mirror.getAnnotationType().toString().equals(name)) {
return annotationKeyValues(mirror);
}
}
throw new IllegalArgumentException(String.format("%s has no annotation %s", element, name));
}
private static Map<String, Object> annotationKeyValues(AnnotationMirror mirror) {
Map<String, Object> result = new LinkedHashMap<>();
for (ExecutableElement key : mirror.getElementValues().keySet()) {
result.put(key.getSimpleName().toString(), mirror.getElementValues().get(key).getValue());
}
return result;
}
}