in src/main/java/org/codehaus/groovy/transform/LogASTTransformation.java [77:193]
public void visit(final ASTNode[] nodes, final SourceUnit sourceUnit) {
init(nodes, sourceUnit);
AnnotatedNode targetClass = (AnnotatedNode) nodes[1];
AnnotationNode logAnnotation = (AnnotationNode) nodes[0];
final LoggingStrategy loggingStrategy = createLoggingStrategy(logAnnotation, sourceUnit.getClassLoader(), compilationUnit.getTransformLoader());
if (loggingStrategy == null) return;
final String logFieldName = lookupLogFieldName(logAnnotation);
final String categoryName = lookupCategoryName(logAnnotation);
final int logFieldModifiers = lookupLogFieldModifiers(targetClass, logAnnotation);
if (!(targetClass instanceof ClassNode))
throw new GroovyBugError("Class annotation " + logAnnotation.getClassNode().getName() + " annotated no Class, this must not happen.");
final ClassNode classNode = (ClassNode) targetClass;
ClassCodeExpressionTransformer transformer = new ClassCodeExpressionTransformer() {
private FieldNode logNode;
@Override
protected SourceUnit getSourceUnit() {
return sourceUnit;
}
@Override
public Expression transform(final Expression exp) {
if (exp == null) return null;
if (exp instanceof MethodCallExpression) {
return transformMethodCallExpression(exp);
}
if (exp instanceof ClosureExpression) {
return transformClosureExpression((ClosureExpression) exp);
}
return super.transform(exp);
}
@Override
public void visitClass(final ClassNode node) {
FieldNode logField = node.getField(logFieldName);
if (logField != null && logField.getOwner().equals(node)) {
addError("Class annotated with Log annotation cannot have log field declared", logField);
} else if (logField != null && !Modifier.isPrivate(logField.getModifiers())) {
addError("Class annotated with Log annotation cannot have log field declared because the field exists in the parent class: " + logField.getOwner().getName(), logField);
} else {
if (loggingStrategy instanceof LoggingStrategyV2) {
LoggingStrategyV2 loggingStrategyV2 = (LoggingStrategyV2) loggingStrategy;
logNode = loggingStrategyV2.addLoggerFieldToClass(node, logFieldName, categoryName, logFieldModifiers);
} else {
// support the old style but they won't be as configurable
logNode = loggingStrategy.addLoggerFieldToClass(node, logFieldName, categoryName);
}
}
super.visitClass(node);
}
private Expression transformClosureExpression(final ClosureExpression exp) {
if (exp.getCode() instanceof BlockStatement) {
BlockStatement code = (BlockStatement) exp.getCode();
super.visitBlockStatement(code);
}
return exp;
}
private Expression transformMethodCallExpression(final Expression exp) {
Expression modifiedCall = addGuard((MethodCallExpression) exp);
return modifiedCall == null ? super.transform(exp) : modifiedCall;
}
private Expression addGuard(final MethodCallExpression mce) {
// only add guard to methods of the form: logVar.logMethod(params)
if (!(mce.getObjectExpression() instanceof VariableExpression)) {
return null;
}
VariableExpression variableExpression = (VariableExpression) mce.getObjectExpression();
if (!variableExpression.getName().equals(logFieldName)
|| !(variableExpression.getAccessedVariable() instanceof DynamicVariable)) {
return null;
}
String methodName = mce.getMethodAsString();
if (methodName == null) return null;
if (!loggingStrategy.isLoggingMethod(methodName)) return null;
// also don't bother with guard if we have "simple" method args
// since there is no saving
if (usesSimpleMethodArgumentsOnly(mce)) return null;
variableExpression.setAccessedVariable(logNode);
return loggingStrategy.wrapLoggingMethodCall(variableExpression, methodName, mce);
}
private boolean usesSimpleMethodArgumentsOnly(final MethodCallExpression mce) {
Expression arguments = mce.getArguments();
if (arguments instanceof TupleExpression) {
TupleExpression tuple = (TupleExpression) arguments;
for (Expression exp : tuple.getExpressions()) {
if (!isSimpleExpression(exp)) return false;
}
return true;
}
return !isSimpleExpression(arguments);
}
private boolean isSimpleExpression(final Expression exp) {
if (exp instanceof ConstantExpression) return true;
if (exp instanceof VariableExpression) return true;
return false;
}
};
transformer.visitClass(classNode);
// GROOVY-6373: references to 'log' field are normally already FieldNodes by now, so revisit scoping
new VariableScopeVisitor(sourceUnit, true).visitClass(classNode);
}