Skip to content

Commit 8f7b796

Browse files
authored
Allow for a few custom Checkstyle rules to be configured (#43731)
Allow for a few custom Checkstyle rules to be configured
1 parent 53c5b61 commit 8f7b796

File tree

9 files changed

+506
-54
lines changed

9 files changed

+506
-54
lines changed

eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/DenyListedWordsCheck.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
import com.puppycrawl.tools.checkstyle.utils.CheckUtil;
1111
import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
1212

13-
import java.util.Collections;
14-
import java.util.HashSet;
15-
import java.util.Set;
13+
import java.util.Arrays;
1614

1715
/**
1816
* Ensure that code is not using words or abbreviations that are deny listed by this Checkstyle. denyListedWords: the
@@ -21,7 +19,7 @@
2119
* Prints out a message stating the location and the class, method or variable as well as the list of deny listed words.
2220
*/
2321
public class DenyListedWordsCheck extends AbstractCheck {
24-
private final Set<String> denyListedWords = new HashSet<>();
22+
private String[] denyListedWords = new String[0];
2523

2624
static final String ERROR_MESSAGE = "%s, All Public API Classes, Fields and Methods should follow "
2725
+ "Camelcase standards for the following words: %s.";
@@ -33,7 +31,7 @@ public class DenyListedWordsCheck extends AbstractCheck {
3331
*/
3432
public final void setDenyListedWords(String... denyListedWords) {
3533
if (denyListedWords != null) {
36-
Collections.addAll(this.denyListedWords, denyListedWords);
34+
this.denyListedWords = Arrays.copyOf(denyListedWords, denyListedWords.length);
3735
}
3836
}
3937

eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/GoodLoggingCheck.java

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,9 @@
1010
import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
1111

1212
import java.util.ArrayDeque;
13-
import java.util.Arrays;
1413
import java.util.Collections;
15-
import java.util.HashSet;
1614
import java.util.Objects;
1715
import java.util.Queue;
18-
import java.util.Set;
1916

2017
/**
2118
* Good Logging Practice:
@@ -29,9 +26,6 @@
2926
* </ol>
3027
*/
3128
public class GoodLoggingCheck extends AbstractCheck {
32-
private static final String CLIENT_LOGGER_PATH = "com.azure.core.util.logging.ClientLogger";
33-
private static final String CLIENT_LOGGER = "ClientLogger";
34-
private static final String LOGGER = "logger";
3529
private static final int[] REQUIRED_TOKENS = new int[]{
3630
TokenTypes.IMPORT,
3731
TokenTypes.INTERFACE_DEF,
@@ -52,9 +46,57 @@ public class GoodLoggingCheck extends AbstractCheck {
5246
// A LIFO queue stores the class names, pop top element if exist the class name AST node
5347
private final Queue<String> classNameDeque = Collections.asLifoQueue(new ArrayDeque<>());
5448
// Collection of Invalid logging packages
55-
private static final Set<String> INVALID_LOGS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
49+
private static final String[] INVALID_LOGS = new String[] {
5650
"org.slf4j", "org.apache.logging.log4j", "java.util.logging"
57-
)));
51+
};
52+
53+
private String fullyQualifiedLoggerName = "com.azure.core.util.logging.ClientLogger";
54+
private String simpleClassName = "ClientLogger";
55+
private String loggerName = "logger";
56+
57+
/**
58+
* Sets the fully qualified logger name.
59+
* <p>
60+
* If not set this will default to {@code com.azure.core.util.logging.ClientLogger}.
61+
*
62+
* @param fullyQualifiedLoggerName the fully qualified logger name.
63+
* @throws IllegalArgumentException if the fully qualified logger name is null or empty.
64+
*/
65+
public final void setFullyQualifiedLoggerName(String fullyQualifiedLoggerName) {
66+
if (fullyQualifiedLoggerName == null || fullyQualifiedLoggerName.isEmpty()) {
67+
throw new IllegalArgumentException("fullyQualifiedLoggerName cannot be null or empty.");
68+
}
69+
70+
this.fullyQualifiedLoggerName = fullyQualifiedLoggerName;
71+
}
72+
73+
/**
74+
* Sets the simple class name for the logger.
75+
* <p>
76+
* If not set this will default to {@code ClientLogger}.
77+
*
78+
* @param simpleClassName the simple class name for the logger.
79+
* @throws IllegalArgumentException if the simple class name is null or empty.
80+
*/
81+
public final void setSimpleClassName(String simpleClassName) {
82+
if (simpleClassName == null || simpleClassName.isEmpty()) {
83+
throw new IllegalArgumentException("simpleClassName cannot be null or empty.");
84+
}
85+
86+
this.simpleClassName = simpleClassName;
87+
}
88+
89+
/**
90+
* Sets the case-insensitive name of the logger instance.
91+
* <p>
92+
* If not set this will default to {@code logger}.
93+
*
94+
* @param loggerName the case-insensitive name of the logger instance.
95+
* @throws IllegalArgumentException if the logger name is null or empty.
96+
*/
97+
public final void setLoggerName(String loggerName) {
98+
this.loggerName = loggerName;
99+
}
58100

59101
@Override
60102
public int[] getDefaultTokens() {
@@ -90,13 +132,13 @@ public void visitToken(DetailAST ast) {
90132
switch (ast.getType()) {
91133
case TokenTypes.IMPORT:
92134
final String importClassPath = FullIdent.createFullIdentBelow(ast).getText();
93-
hasClientLoggerImported = hasClientLoggerImported || importClassPath.equals(CLIENT_LOGGER_PATH);
135+
hasClientLoggerImported = hasClientLoggerImported || importClassPath.equals(fullyQualifiedLoggerName);
94136

95-
INVALID_LOGS.forEach(item -> {
96-
if (importClassPath.startsWith(item)) {
97-
log(ast, String.format(NOT_CLIENT_LOGGER_ERROR, "external logger", CLIENT_LOGGER_PATH, item));
137+
for (String invalidLog : INVALID_LOGS) {
138+
if (importClassPath.startsWith(invalidLog)) {
139+
log(ast, String.format(NOT_CLIENT_LOGGER_ERROR, "external logger", fullyQualifiedLoggerName, invalidLog));
98140
}
99-
});
141+
}
100142
break;
101143
case TokenTypes.CLASS_DEF:
102144
case TokenTypes.INTERFACE_DEF:
@@ -116,7 +158,7 @@ public void visitToken(DetailAST ast) {
116158
}
117159
final String methodCallName = FullIdent.createFullIdentBelow(dotToken).getText();
118160
if (methodCallName.startsWith("System.out") || methodCallName.startsWith("System.err")) {
119-
log(ast, String.format(NOT_CLIENT_LOGGER_ERROR, "Java System", CLIENT_LOGGER_PATH, methodCallName));
161+
log(ast, String.format(NOT_CLIENT_LOGGER_ERROR, "Java System", fullyQualifiedLoggerName, methodCallName));
120162
}
121163
break;
122164
default:
@@ -137,7 +179,7 @@ private boolean isTypeClientLogger(DetailAST varDefAST) {
137179
return false;
138180
}
139181
return TokenUtil.findFirstTokenByPredicate(typeAST, node ->
140-
node.getType() == TokenTypes.IDENT && node.getText().equals(CLIENT_LOGGER)
182+
node.getType() == TokenTypes.IDENT && node.getText().equals(simpleClassName)
141183
).isPresent();
142184
}
143185

@@ -149,7 +191,7 @@ private boolean isTypeClientLogger(DetailAST varDefAST) {
149191
private void checkLoggerInstantiation(DetailAST literalNewToken) {
150192
final DetailAST identToken = literalNewToken.findFirstToken(TokenTypes.IDENT);
151193
// Not ClientLogger instance
152-
if (identToken == null || !identToken.getText().equals(CLIENT_LOGGER)) {
194+
if (identToken == null || !identToken.getText().equals(simpleClassName)) {
153195
return;
154196
}
155197
// LITERAL_NEW node always has ELIST node below
@@ -180,8 +222,8 @@ private void checkLoggerNameMatch(DetailAST varToken) {
180222
}
181223
// Check if the Logger instance named as 'logger/LOGGER'.
182224
final DetailAST identAST = varToken.findFirstToken(TokenTypes.IDENT);
183-
if (identAST != null && !identAST.getText().equalsIgnoreCase(LOGGER)) {
184-
log(varToken, String.format(LOGGER_NAME_ERROR, LOGGER, identAST.getText()));
225+
if (identAST != null && !identAST.getText().equalsIgnoreCase(loggerName)) {
226+
log(varToken, String.format(LOGGER_NAME_ERROR, loggerName, identAST.getText()));
185227
}
186228
}
187229
}

eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/NoImplInPublicAPI.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public class NoImplInPublicAPI extends AbstractCheck {
3737
+ "for public API. " + ALTERNATIVE_MOVE_TO_PUBLIC_API;
3838

3939
// Pattern that matches either an import statement or a fully-qualified type reference for being implementation.
40-
private static final Pattern IMPLEMENTATION_CLASS = Pattern.compile("com\\.azure.*?\\.implementation.*?\\.(\\w+)");
40+
private static final Pattern IMPLEMENTATION_CLASS = Pattern.compile(".*?\\.implementation.*?\\.(\\w+)");
4141

4242
private Set<String> implementationClassSet = new HashSet<>();
4343

eng/code-quality-reports/src/main/java/com/azure/tools/checkstyle/checks/ThrowFromClientLoggerCheck.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
public class ThrowFromClientLoggerCheck extends AbstractCheck {
2727
private static final String LOGGER_LOG_EXCEPTION_AS_ERROR = "logger.logExceptionAsError";
2828
private static final String LOGGER_LOG_THROWABLE_AS_ERROR = "logger.logThrowableAsError";
29-
private static final String LOGGING_BUILDER_LOG_THROWABLE_AS_ERROR = "logger.atError().log";
29+
private static final String LOGGING_BUILDER_LOG_THROWABLE_AS_ERROR = "logger.atError().log";
3030
private static final String LOGGER_LOG_EXCEPTION_AS_WARNING = "logger.logExceptionAsWarning";
31-
private static final String LOGGER_LOG_THROWABLE_AS_WARNING = "logger.logThrowableAsWarning";
31+
private static final String LOGGER_LOG_THROWABLE_AS_WARNING = "logger.logThrowableAsWarning";
3232
private static final String LOGGING_BUILDER_LOG_THROWABLE_AS_WARNING = "logger.atWarning().log";
3333

3434
static final String THROW_LOGGER_EXCEPTION_MESSAGE = String.format("Directly throwing an exception is disallowed. "
@@ -98,7 +98,7 @@ public void visitToken(DetailAST token) {
9898
case TokenTypes.LITERAL_THROW:
9999
// Skip check if the throw exception from static class, constructor or static method
100100
if (classStaticDeque.isEmpty() || classStaticDeque.peek() || isInConstructor
101-
|| methodStaticDeque.isEmpty() || methodStaticDeque.peek()
101+
|| methodStaticDeque.isEmpty() || methodStaticDeque.peek()
102102
|| findLogMethodIdentifier(token)) {
103103
return;
104104
}
@@ -126,7 +126,7 @@ public void visitToken(DetailAST token) {
126126
}
127127

128128
/*
129-
* Checks if the expression includes call to log(), which verifies logging builder call
129+
* Checks if the expression includes call to log(), which verifies logging builder call
130130
* e.g. logger.atError().log(ex)
131131
*/
132132
private static boolean findLogMethodIdentifier(DetailAST root) {

0 commit comments

Comments
 (0)