package org.ovirt.checkstyle.checks; import java.util.LinkedList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; public class NlsCheck extends AbstractCheck { private static final Pattern patternString = Pattern.compile("[\"][^\"]*[^\\\\][\"]"); private boolean run = false; @Override public int[] getDefaultTokens() { return new int[0]; } @Override public void beginTree(DetailAST aRootAST) { if (!run){ return; } if (!getFileContents().getFileName().matches(".*\\.java")) { return; } int i = 0; boolean startAnnotation = false; for (String lineText : getLines()) { ++i; // Ignore strings passed as annotation parameters if (lineText.matches("^\\s*@.*")) { int parenthesesStart = lineText.indexOf("("); while (parenthesesStart != -1 && getFileContents().hasIntersectionWithComment(i, parenthesesStart, i, parenthesesStart)){ parenthesesStart = lineText.indexOf("(", parenthesesStart + 1); } if (parenthesesStart != -1){ startAnnotation = true; } } List<QuotedString> stringList = new LinkedList<>(); Matcher matcher = patternString.matcher(lineText); while (matcher.find()) { if (getFileContents().hasIntersectionWithComment(i, matcher.start(), i, matcher.end())) { continue; } stringList.add(new QuotedString(matcher.group(), matcher .start(), matcher.end())); } if (startAnnotation) { int endAnno = hasEndAnno(lineText, i, stringList); if (endAnno != -1) { startAnnotation = false; // maybe the rest of the line has quoted string List<QuotedString> tmpStringList = new LinkedList<>(); for (QuotedString quotedString : stringList) { if (quotedString.startIndex > endAnno) { tmpStringList.add(quotedString); } } stringList = tmpStringList; } else { continue; } } int j = 0; for (QuotedString str : stringList) { ++j; Pattern patternNls = Pattern.compile("\\$NON-NLS-" + j + "\\$"); Matcher matcherNls = patternNls.matcher(lineText); int matchNum = 0; while (matcherNls.find()) { ++matchNum; } if (matchNum != 1) { log(i, "String on line " + i + " (at index " + str.startIndex + ") is non-localized.\n" + "Please localize it via Constants/Messages interface " + "or use //$NON-NLS-" + j + "$" + " comment to indicate that it shouldn't be localized."); } } } } int hasEndAnno(String lineText, int lineNum, List<QuotedString> quotedStrings) { int startIndex = lineText.indexOf(")"); while (startIndex != -1) { boolean isValidEnd = true; for (QuotedString quoted : quotedStrings) { if (startIndex >= quoted.startIndex && startIndex <= quoted.endIndex) { isValidEnd = false; break; } } if (getFileContents().hasIntersectionWithComment(lineNum, startIndex, lineNum, startIndex)) { isValidEnd = false; } if (isValidEnd) { return startIndex; } startIndex = lineText.indexOf(")", startIndex + 1); } return -1; } private static class QuotedString { String text; int startIndex; int endIndex; public QuotedString(String text, int startIndex, int endIndex) { this.text = text; this.startIndex = startIndex; this.endIndex = endIndex; } @Override public String toString() { return String.format("%s [%d:%d]", text, startIndex, endIndex); } } public void setRun(boolean run) { this.run = run; } }