/*
* Copyright 2014 - 2017 Blazebit.
*
* 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.blazebit.persistence.checkstyle;
import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
import com.puppycrawl.tools.checkstyle.api.DetailAST;
import com.puppycrawl.tools.checkstyle.api.FileContents;
import com.puppycrawl.tools.checkstyle.api.Scope;
import com.puppycrawl.tools.checkstyle.api.TextBlock;
import com.puppycrawl.tools.checkstyle.api.TokenTypes;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTag;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTagInfo;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTags;
import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTypeCheck;
import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
import com.puppycrawl.tools.checkstyle.utils.JavadocUtils;
import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
import java.util.List;
import java.util.regex.Pattern;
/**
* Simple checkstyle check that asserts the since tag format. Heavily inspired by {@link JavadocTypeCheck}.
*
* @author Christian Beikov
* @since 1.2.0
*/
public class JavadocSinceCheck extends AbstractCheck {
private Scope scope = Scope.PRIVATE;
private Scope excludeScope;
private Pattern sinceFormatPattern;
private String sinceFormat;
@Override
public int[] getDefaultTokens() {
return new int[]{
TokenTypes.CLASS_DEF,
TokenTypes.INTERFACE_DEF,
TokenTypes.ENUM_DEF,
TokenTypes.ANNOTATION_DEF,
};
}
/**
* Sets the scope to check.
*
* @param from string to set scope from
*/
public void setScope(String from) {
scope = Scope.getInstance(from);
}
/**
* Set the excludeScope.
*
* @param excludeScope a {@code String} value
*/
public void setExcludeScope(String excludeScope) {
this.excludeScope = Scope.getInstance(excludeScope);
}
/**
* Set the sinceFormat.
*
* @param sinceFormat a {@code String} value
*/
public void setSinceFormat(String sinceFormat) {
this.sinceFormat = sinceFormat;
this.sinceFormatPattern = CommonUtils.createPattern(sinceFormat);
}
@Override
public void visitToken(final DetailAST ast) {
if (shouldCheck(ast)) {
final FileContents contents = getFileContents();
final int lineNo = ast.getLineNo();
final TextBlock textBlock = contents.getJavadocBefore(lineNo);
if (textBlock == null) {
log(lineNo, JavadocTypeCheck.MSG_JAVADOC_MISSING);
} else {
final List<JavadocTag> tags = getJavadocTags(textBlock);
if (ScopeUtils.isOuterMostType(ast)) {
// don't check author/version for inner classes
checkTag(lineNo, tags, JavadocTagInfo.SINCE.getName(),
sinceFormatPattern, sinceFormat);
}
}
}
}
private boolean shouldCheck(final DetailAST ast) {
final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS);
final Scope declaredScope = ScopeUtils.getScopeFromMods(mods);
final Scope customScope;
if (ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) {
customScope = Scope.PUBLIC;
} else {
customScope = declaredScope;
}
final Scope surroundingScope = ScopeUtils.getSurroundingScope(ast);
return customScope.isIn(scope)
&& (surroundingScope == null || surroundingScope.isIn(scope))
&& (excludeScope == null
|| !customScope.isIn(excludeScope)
|| surroundingScope != null
&& !surroundingScope.isIn(excludeScope));
}
private List<JavadocTag> getJavadocTags(TextBlock textBlock) {
final JavadocTags tags = JavadocUtils.getJavadocTags(textBlock,
JavadocUtils.JavadocTagType.BLOCK);
return tags.getValidTags();
}
private void checkTag(int lineNo, List<JavadocTag> tags, String tagName,
Pattern formatPattern, String format) {
if (formatPattern != null) {
int tagCount = 0;
final String tagPrefix = "@";
for (int i = tags.size() - 1; i >= 0; i--) {
final JavadocTag tag = tags.get(i);
if (tag.getTagName().equals(tagName)) {
tagCount++;
if (!formatPattern.matcher(tag.getFirstArg()).find()) {
log(lineNo, JavadocTypeCheck.MSG_TAG_FORMAT, tagPrefix + tagName, format);
}
}
}
if (tagCount == 0) {
log(lineNo, JavadocTypeCheck.MSG_MISSING_TAG, tagPrefix + tagName);
}
}
}
}