/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.source.formatter.checks;
import com.liferay.portal.kernel.util.CharPool;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.tools.ToolsUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Hugo Huijser
*/
public abstract class EmptyLinesCheck extends BaseFileCheck {
protected String fixEmptyLinesBetweenTags(String content) {
Matcher matcher = _emptyLineBetweenTagsPattern.matcher(content);
while (matcher.find()) {
String tabs1 = matcher.group(1);
String tabs2 = matcher.group(4);
if (!tabs1.equals(tabs2)) {
continue;
}
String lineBreaks = matcher.group(3);
String tagName1 = matcher.group(2);
String tagName2 = matcher.group(5);
if (tagName1.endsWith(":when") ||
(tagName1.matches("dd|dt|li|span|td|th|tr") &&
tagName2.matches("dd|dt|li|span|td|th|tr"))) {
if (lineBreaks.equals("\n\n")) {
return StringUtil.replaceFirst(
content, "\n\n", "\n", matcher.end(1));
}
}
else if (lineBreaks.equals("\n")) {
return StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.end(1));
}
}
matcher = _missingEmptyLineBetweenTagsPattern1.matcher(content);
while (matcher.find()) {
String tabs1 = matcher.group(1);
String tabs2 = matcher.group(2);
if (tabs1.equals(tabs2)) {
return StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.end(1));
}
}
matcher = _missingEmptyLineBetweenTagsPattern2.matcher(content);
while (matcher.find()) {
String tabs1 = matcher.group(1);
String tabs2 = matcher.group(2);
if (tabs1.equals(tabs2)) {
return StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.end(1));
}
}
return content;
}
protected String fixEmptyLinesInMultiLineTags(String content) {
Matcher matcher = _emptyLineInMultiLineTagsPattern.matcher(content);
if (matcher.find()) {
return StringUtil.replaceFirst(
content, "\n\n", "\n", matcher.start());
}
return content;
}
protected String fixEmptyLinesInNestedTags(String content) {
content = fixEmptyLinesInNestedTags(
content, _emptyLineInNestedTagsPattern1, true);
return fixEmptyLinesInNestedTags(
content, _emptyLineInNestedTagsPattern2, false);
}
protected String fixEmptyLinesInNestedTags(
String content, Pattern pattern, boolean startTag) {
Matcher matcher = pattern.matcher(content);
while (matcher.find()) {
String tabs2 = null;
if (startTag) {
String secondLine = matcher.group(3);
if (secondLine.equals("<%") || secondLine.startsWith("<%--") ||
secondLine.startsWith("<!--")) {
continue;
}
tabs2 = matcher.group(2);
}
else {
String firstLine = matcher.group(2);
if (firstLine.equals("%>") || firstLine.endsWith("-->")) {
continue;
}
tabs2 = matcher.group(3);
}
String tabs1 = matcher.group(1);
if ((startTag && ((tabs1.length() + 1) == tabs2.length())) ||
(!startTag && ((tabs1.length() - 1) == tabs2.length()))) {
content = StringUtil.replaceFirst(
content, StringPool.NEW_LINE, StringPool.BLANK,
matcher.end(1));
}
}
return content;
}
protected String fixIncorrectEmptyLineBeforeCloseCurlyBrace(
String content) {
Matcher matcher1 = _incorrectCloseCurlyBracePattern1.matcher(content);
while (matcher1.find()) {
if (!isJavaSource(content, matcher1.end())) {
continue;
}
String lastLine = StringUtil.trimLeading(matcher1.group(1));
if (lastLine.startsWith("// ")) {
continue;
}
String tabs = matcher1.group(2);
int tabCount = tabs.length();
int pos = matcher1.start();
while (true) {
pos = content.lastIndexOf("\n" + tabs, pos - 1);
if (content.charAt(pos + tabCount + 1) == CharPool.TAB) {
continue;
}
String codeBlock = content.substring(pos + 1, matcher1.end());
String firstLine = codeBlock.substring(
0, codeBlock.indexOf(CharPool.NEW_LINE) + 1);
Matcher matcher2 = _incorrectCloseCurlyBracePattern2.matcher(
firstLine);
if (matcher2.find()) {
break;
}
return StringUtil.replaceFirst(
content, "\n\n" + tabs + "}\n", "\n" + tabs + "}\n", pos);
}
}
return content;
}
protected String fixMissingEmptyLineAfterSettingVariable(String content) {
Matcher matcher = _setVariablePattern.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
if (content.charAt(matcher.end()) == CharPool.NEW_LINE) {
continue;
}
int x = content.indexOf(";\n", matcher.end());
if (x == -1) {
return content;
}
String nextCommand = content.substring(matcher.end(), x + 1);
if (nextCommand.contains("{\n") ||
nextCommand.matches("\t*%>[\\S\\s]*")) {
continue;
}
String variableName = matcher.group(1);
Pattern pattern2 = Pattern.compile("\\W(" + variableName + ")\\.");
Matcher matcher2 = pattern2.matcher(nextCommand);
if (!matcher2.find()) {
continue;
}
x = matcher2.start(1);
if (ToolsUtil.isInsideQuotes(nextCommand, x)) {
continue;
}
x += matcher.end();
int y = content.lastIndexOf("\ttry (", x);
if (y != -1) {
int z = content.indexOf(") {\n", y);
if (z > x) {
continue;
}
}
return StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.end(2));
}
return content;
}
protected String fixMissingEmptyLines(String content) {
outerLoop:
while (true) {
Matcher matcher = _missingEmptyLinePattern1.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
if (getLevel(matcher.group()) == 0) {
content = StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.start());
continue outerLoop;
}
}
matcher = _missingEmptyLinePattern2.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
String match = matcher.group();
if (!match.contains(StringPool.OPEN_PARENTHESIS)) {
continue;
}
String whitespace = matcher.group(1);
int x = content.indexOf(
whitespace + StringPool.CLOSE_CURLY_BRACE + "\n",
matcher.end());
int y = content.indexOf(
whitespace + StringPool.CLOSE_CURLY_BRACE + "\n\n",
matcher.end());
if ((x != -1) && (x != y)) {
content = StringUtil.replaceFirst(
content, "\n", "\n\n", x + 1);
continue outerLoop;
}
}
matcher = _missingEmptyLinePattern3.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
if ((getLevel(matcher.group()) != 0) &&
(content.charAt(matcher.end()) != CharPool.NEW_LINE)) {
content = StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.end() - 1);
continue outerLoop;
}
}
matcher = _missingEmptyLinePattern4.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.start() + 1);
continue outerLoop;
}
matcher = _missingEmptyLinePattern5.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.start() + 1);
continue outerLoop;
}
matcher = _missingEmptyLinePattern6.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.start());
continue outerLoop;
}
matcher = _missingEmptyLinePattern7.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", "\n\n", matcher.start() + 1);
continue outerLoop;
}
break;
}
return content;
}
protected String fixRedundantEmptyLines(String content) {
outerLoop:
while (true) {
Matcher matcher = _redundantEmptyLinePattern1.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", StringPool.BLANK, matcher.start());
continue outerLoop;
}
matcher = _redundantEmptyLinePattern2.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", StringPool.BLANK, matcher.end() - 1);
continue outerLoop;
}
matcher = _redundantEmptyLinePattern3.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", StringPool.BLANK, matcher.start() + 1);
continue outerLoop;
}
matcher = _redundantEmptyLinePattern4.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", StringPool.BLANK, matcher.start());
continue outerLoop;
}
matcher = _redundantEmptyLinePattern5.matcher(content);
while (matcher.find()) {
if (!isJavaSource(content, matcher.start())) {
continue;
}
content = StringUtil.replaceFirst(
content, "\n", StringPool.BLANK, matcher.start());
continue outerLoop;
}
break;
}
return content;
}
protected boolean isJavaSource(String content, int pos) {
return true;
}
private final Pattern _emptyLineBetweenTagsPattern = Pattern.compile(
"\n(\t*)</([-\\w:]+)>(\n*)(\t*)<([-\\w:]+)[> \n]");
private final Pattern _emptyLineInMultiLineTagsPattern = Pattern.compile(
"\n\t*<[-\\w:#]+\n\n\t*\\w");
private final Pattern _emptyLineInNestedTagsPattern1 = Pattern.compile(
"\n(\t*)(?:<\\w.*[^/])?>\n\n(\t*)(<.*)\n");
private final Pattern _emptyLineInNestedTagsPattern2 = Pattern.compile(
"\n(\t*)(.*>)\n\n(\t*)</.*(\n|$)");
private final Pattern _incorrectCloseCurlyBracePattern1 = Pattern.compile(
"\n(.+)\n\n(\t+)}\n");
private final Pattern _incorrectCloseCurlyBracePattern2 = Pattern.compile(
"(\t| )@?(class|enum|interface|new)\\s");
private final Pattern _missingEmptyLineBetweenTagsPattern1 =
Pattern.compile("\n(\t*)/>\n(\t*)<[-\\w:]+[> \n]");
private final Pattern _missingEmptyLineBetweenTagsPattern2 =
Pattern.compile(
"\n(\t*)<.* />\n(\t*)<([-\\w:]+|\\w((?!</| />).)*[^/]>)\n");
private final Pattern _missingEmptyLinePattern1 = Pattern.compile(
"(\t| = |return )new .*\\(.*\\) \\{\n\t+[^{\t]");
private final Pattern _missingEmptyLinePattern2 = Pattern.compile(
"(\n\t*)(public|private|protected) [^;]+? \\{");
private final Pattern _missingEmptyLinePattern3 = Pattern.compile(
"\n.*\\) \\{\n");
private final Pattern _missingEmptyLinePattern4 = Pattern.compile(
"\n\t*// .*\n[\t ]*(?!// )\\S");
private final Pattern _missingEmptyLinePattern5 = Pattern.compile(
"\n[\t ]*(?!// )\\S.*\n\t*// ");
private final Pattern _missingEmptyLinePattern6 = Pattern.compile(
"[^{:/\n]\n\t*(for|if|try) \\(");
private final Pattern _missingEmptyLinePattern7 = Pattern.compile(
"[\t\n]\\}\n[\t ]*(?!(/\\*|\\}|\\)|//|catch |else |finally |while ))" +
"\\S");
private final Pattern _redundantEmptyLinePattern1 = Pattern.compile(
"\n\npublic ((abstract|static) )*(class|enum|interface) ");
private final Pattern _redundantEmptyLinePattern2 = Pattern.compile(
" \\* @author .*\n \\*\\/\n\n");
private final Pattern _redundantEmptyLinePattern3 = Pattern.compile(
"[\n\t](catch |else |finally |for |if |try |while ).*\\{\n\n\t+\\w");
private final Pattern _redundantEmptyLinePattern4 = Pattern.compile(
"\\{\n\n\t*\\}");
private final Pattern _redundantEmptyLinePattern5 = Pattern.compile(
"\\}\n\n\t*(catch|else( if)?|finally) [\\(\\{]");
private final Pattern _setVariablePattern = Pattern.compile(
"\t[A-Z]\\w+ (\\w+) =\\s+((?!\\{\n).)*?;\n", Pattern.DOTALL);
}