package org.infernus.idea.checkstyle.checks;
import java.util.concurrent.atomic.AtomicReference;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.infernus.idea.checkstyle.CheckstyleProjectService;
import org.infernus.idea.checkstyle.csapi.CheckstyleInternalObject;
import org.infernus.idea.checkstyle.csapi.ConfigVisitor;
import org.infernus.idea.checkstyle.csapi.ConfigurationModule;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Extra logic for the JavadocPackageCheck check.
*/
public final class JavadocPackageCheck implements Check {
private static final String CHECK_PACKAGE_INFO =
"com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck";
private static final String MODULE_NAME = "JavadocPackage";
private static final String PACKAGE_HTML_FILE = "package.html";
private static final String PACKAGE_INFO_FILE = "package-info.java";
private boolean usingLegacyPackage;
private final Project project;
public JavadocPackageCheck(@NotNull final Project pProject) {
project = pProject;
}
@Override
public String getShortName() {
return MODULE_NAME;
}
@Override
public String getFullyQualifiedName() {
return CHECK_PACKAGE_INFO;
}
/**
* Retrieve the allowLegacy flag for handling javadoc package info from a CheckStyle configuration.
*/
public void configure(@NotNull final CheckstyleInternalObject config) {
final String stringValue = parsePackageInfoLegacy(config);
usingLegacyPackage = null != stringValue && Boolean.parseBoolean(stringValue);
}
public boolean process(@NotNull final PsiFile file, @NotNull final String pEventSourceName) {
if (!CHECK_PACKAGE_INFO.equals(pEventSourceName)) {
return true;
}
PsiElement currentSibling = findFirstSibling(file);
while (currentSibling != null) {
if (currentSibling.isPhysical() && currentSibling.isValid() && currentSibling instanceof PsiFile) {
final String siblingName = ((PsiFile) currentSibling).getName();
if (PACKAGE_INFO_FILE.equals(siblingName)
|| (usingLegacyPackage && PACKAGE_HTML_FILE.equals(siblingName))) {
return false;
}
}
currentSibling = currentSibling.getNextSibling();
}
return true;
}
private PsiElement findFirstSibling(@NotNull final PsiFile psiFile) {
PsiElement currentSibling = psiFile;
while (currentSibling != null && currentSibling.getPrevSibling() != null) {
currentSibling = currentSibling.getPrevSibling();
}
return currentSibling;
}
/**
* Retrieve the allowLegacy flag as a String for handling javadoc package info from a CheckStyle configuration.
*
* @param config the checkstyle configuration.
* @return the allowLegacy flag in String form.
*/
@Nullable
private String parsePackageInfoLegacy(final CheckstyleInternalObject config) {
if (config == null) {
return null;
}
// TODO Going through the whole config is somewhat inefficient here; might do this centrally and only
// once. Currently we don't care because there is only one such class.
final CheckstyleProjectService csService = CheckstyleProjectService.getInstance(project);
final AtomicReference<String> value = new AtomicReference<>();
csService.getCheckstyleInstance().peruseConfiguration(config, new ConfigVisitor() {
@Override
public void visit(@NotNull final ConfigurationModule pModule) {
if (MODULE_NAME.equals(pModule.getName()) || CHECK_PACKAGE_INFO.equals(pModule.getName())) {
value.set(pModule.getProperties().get("allowLegacy"));
// TODO This means that if for some reasons this attribute appears multiple times, the last
// occurrence wins. Instead, we should check if 'allowLegacy' is true anywhere.
}
}
});
return value.get();
}
}