/*
* Copyright 2014 Lukas Krejci
*
* 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.revapi.java.checks.common;
import java.util.Collections;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.Modifier;
import org.revapi.Difference;
import org.revapi.java.spi.CheckBase;
import org.revapi.java.spi.Code;
import org.revapi.java.spi.JavaModelElement;
/**
* @author Lukas Krejci
* @since 0.1
*/
public abstract class VisibilityChanged extends CheckBase {
private final Code code;
private final boolean reportIncrease;
protected VisibilityChanged(Code code, boolean reportIncrease) {
this.code = code;
this.reportIncrease = reportIncrease;
}
protected final void doVisit(JavaModelElement oldElement, JavaModelElement newElement) {
if (oldElement != null && newElement != null) {
boolean oldAccessible = isAccessible(oldElement);
boolean newAccessible = isAccessible(newElement);
//check if both are accessible or if they differ.. don't check if they're both private
if (oldAccessible || newAccessible) {
pushActive(oldElement, newElement);
}
}
}
@Override
protected final List<Difference> doEnd() {
CheckBase.ActiveElements<JavaModelElement> elements = popIfActive();
if (elements != null) {
Modifier oldVisibility = getVisibility(elements.oldElement.getDeclaringElement());
Modifier newVisibility = getVisibility(elements.newElement.getDeclaringElement());
//public == 0, private == 3
if (isProblem(getModifierRank(oldVisibility), getModifierRank(newVisibility))) {
return Collections.singletonList(report(elements, oldVisibility, newVisibility));
}
}
return null;
}
private boolean isProblem(int oldVisibilityRank, int newVisibilityRank) {
return (reportIncrease && oldVisibilityRank > newVisibilityRank) ||
(!reportIncrease && oldVisibilityRank < newVisibilityRank);
}
private Modifier getVisibility(Element t) {
for (Modifier m : t.getModifiers()) {
if (m == Modifier.PUBLIC || m == Modifier.PROTECTED || m == Modifier.PRIVATE) {
return m;
}
}
return null;
}
private int getModifierRank(Modifier modifier) {
if (modifier == null) {
//package private
return 2;
}
switch (modifier) {
case PUBLIC:
return 0;
case PROTECTED:
return 1;
case PRIVATE:
return 3;
default:
return Integer.MAX_VALUE;
}
}
private Difference report(ActiveElements<?> els, Modifier oldVisibility, Modifier newVisibility) {
return createDifference(code, Code.attachmentsFor(els.oldElement, els.newElement,
"oldVisibility", modifier(oldVisibility),
"newVisibility", modifier(newVisibility)));
}
private String modifier(Modifier m) {
return m == null ? "package" : m.name().toLowerCase();
}
}