blob: 4a765a9e5b91362b5d70bf918e1b5858297d5753 [file] [log] [blame]
/* *******************************************************************
* Copyright (c) 2002 Palo Alto Research Center, Incorporated (PARC).
* All rights reserved.
* This program and the accompanying materials are made available
* under the terms of the Eclipse Public License v1.0
* which accompanies this distribution and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* PARC initial implementation
* ******************************************************************/
package org.aspectj.weaver;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.aspectj.bridge.ISourceLocation;
import org.aspectj.weaver.patterns.DeclareErrorOrWarning;
import org.aspectj.weaver.patterns.PerClause;
import org.aspectj.weaver.patterns.Pointcut;
/**
* Representation of a shadow munger for a declare error or warning declaration.
*
* @author Andy Clement
*/
public class Checker extends ShadowMunger {
private boolean isError; // if not error then it is a warning
private String message;
private volatile int hashCode = -1;
@SuppressWarnings("unused")
private Checker() {
}
/**
* Create a Checker for a declare error or declare warning.
*
* @param deow the declare error or declare warning for which to create the checker munger
*/
public Checker(DeclareErrorOrWarning deow) {
super(deow.getPointcut(), deow.getStart(), deow.getEnd(), deow.getSourceContext(), ShadowMungerDeow);
this.message = deow.getMessage();
this.isError = deow.isError();
}
/**
* Only used when filling in a parameterized Checker
*/
private Checker(Pointcut pointcut, int start, int end, ISourceContext context, String message, boolean isError) {
super(pointcut, start, end, context, ShadowMungerDeow);
this.message = message;
this.isError = isError;
}
public boolean isError() {
return isError;
}
public String getMessage(Shadow shadow) {
return format(this.message, shadow);
}
@Override
public void specializeOn(Shadow shadow) {
throw new IllegalStateException("Cannot call specializeOn(...) for a Checker");
}
@Override
public boolean implementOn(Shadow shadow) {
throw new IllegalStateException("Cannot call implementOn(...) for a Checker");
}
/**
* Determine if the Checker matches at a shadow. If it does then we can immediately report the message. Currently, there can
* never be a non-statically determinable match.
*
* @param shadow the shadow which to match against
* @param world the world through which to access message handlers
*/
@Override
public boolean match(Shadow shadow, World world) {
if (super.match(shadow, world)) {
world.reportCheckerMatch(this, shadow);
}
return false;
}
// implementation for PartialOrder.PartialComparable
public int compareTo(Object other) {
return 0;
}
@Override
public boolean mustCheckExceptions() {
return true;
}
@Override
public Collection<ResolvedType> getThrownExceptions() {
return Collections.emptyList();
}
// FIXME this perhaps ought to take account of the other fields in advice (use super.equals?)
@Override
public boolean equals(Object other) {
if (!(other instanceof Checker)) {
return false;
}
Checker o = (Checker) other;
return o.isError == isError && ((o.pointcut == null) ? (pointcut == null) : o.pointcut.equals(pointcut));
}
@Override
public int hashCode() {
if (hashCode == -1) {
int result = 17;
result = 37 * result + (isError ? 1 : 0);
result = 37 * result + ((pointcut == null) ? 0 : pointcut.hashCode());
hashCode = result;
}
return hashCode;
}
/**
* Parameterize the Checker by parameterizing the pointcut
*/
@Override
public ShadowMunger parameterizeWith(ResolvedType declaringType, Map<String, UnresolvedType> typeVariableMap) {
Checker ret = new Checker(this.pointcut.parameterizeWith(typeVariableMap, declaringType.getWorld()), this.start, this.end,
this.sourceContext, this.message, this.isError);
return ret;
}
/**
* Concretize this Checker by concretizing the pointcut
*/
@Override
public ShadowMunger concretize(ResolvedType theAspect, World world, PerClause clause) {
this.pointcut = this.pointcut.concretize(theAspect, getDeclaringType(), 0, this);
this.hashCode = -1;
return this;
}
@Override
public ResolvedType getConcreteAspect() {
return getDeclaringType();
}
// public void write(DataOutputStream stream) throws IOException {
// super.write(stream);
// stream.writeBoolean(isError);
// stream.writeUTF(message);
// }
//
// public static Checker read(DataInputStream stream, World world) throws IOException {
// Checker checker = new Checker();
// checker.isError = stream.readBoolean();
// checker.message = stream.readUTF();
// return checker;
// }
// Return the next non-escaped (with a '\') open curly
private int nextCurly(String string, int pos) {
do {
int curlyIndex = string.indexOf('{', pos);
if (curlyIndex == -1) {
return -1;
}
if (curlyIndex == 0) {
return 0;
}
if (string.charAt(curlyIndex - 1) != '\\') {
return curlyIndex;
}
pos = curlyIndex + 1;
} while (pos < string.length());
return -1;
}
private String format(String msg, Shadow shadow) {
int pos = 0;
int curlyIndex = nextCurly(msg, 0);
if (curlyIndex == -1) {
// was there an escaped one?
if (msg.indexOf('{') != -1) {
return msg.replace("\\{", "{");
} else {
return msg;
}
}
StringBuffer ret = new StringBuffer();
while (curlyIndex >= 0) {
if (curlyIndex > 0) {
ret.append(msg.substring(pos, curlyIndex).replace("\\{", "{"));
}
int endCurly = msg.indexOf('}', curlyIndex);
if (endCurly == -1) {
// wasn't closed properly - ignore it
ret.append('{');
pos = curlyIndex + 1;
} else {
ret.append(getValue(msg.substring(curlyIndex + 1, endCurly), shadow));
}
pos = endCurly + 1;
curlyIndex = nextCurly(msg, pos);
}
ret.append(msg.substring(pos, msg.length()));
return ret.toString();
}
/**
* @param buf the buffer in which to insert the substitution
* @param shadow shadow from which to draw context info
* @param c the substitution character
*/
private String getValue(String key, Shadow shadow) {
if (key.equalsIgnoreCase("joinpoint")) {
return shadow.toString();
} else if (key.equalsIgnoreCase("joinpoint.kind")) {
return shadow.getKind().getName();
} else if (key.equalsIgnoreCase("joinpoint.enclosingclass")) {
return shadow.getEnclosingType().getName();
} else if (key.equalsIgnoreCase("joinpoint.enclosingmember.name")) {
Member member = shadow.getEnclosingCodeSignature();
if (member==null) {
return "";
} else {
return member.getName();
}
} else if (key.equalsIgnoreCase("joinpoint.enclosingmember")) {
Member member = shadow.getEnclosingCodeSignature();
if (member==null) {
return "";
} else {
return member.toString();
}
} else if (key.equalsIgnoreCase("joinpoint.signature")) {
return shadow.getSignature().toString();
} else if (key.equalsIgnoreCase("joinpoint.signature.declaringtype")) {
return shadow.getSignature().getDeclaringType().toString();
} else if (key.equalsIgnoreCase("joinpoint.signature.name")) {
return shadow.getSignature().getName();
} else if (key.equalsIgnoreCase("joinpoint.sourcelocation.sourcefile")) {
ISourceLocation loc = shadow.getSourceLocation();
if ((loc != null) && (loc.getSourceFile() != null)) {
return loc.getSourceFile().toString();
} else {
return "UNKNOWN";
}
} else if (key.equalsIgnoreCase("joinpoint.sourcelocation.line")) {
ISourceLocation loc = shadow.getSourceLocation();
if (loc != null) {
return Integer.toString(loc.getLine());
} else {
return "-1";
}
} else if (key.equalsIgnoreCase("advice.aspecttype")) {
return getDeclaringType().getName();
} else if (key.equalsIgnoreCase("advice.sourcelocation.line")) {
ISourceLocation loc = getSourceLocation();
if ((loc != null) && (loc.getSourceFile() != null)) {
return Integer.toString(loc.getLine());
} else {
return "-1";
}
} else if (key.equalsIgnoreCase("advice.sourcelocation.sourcefile")) {
ISourceLocation loc = getSourceLocation();
if ((loc != null) && (loc.getSourceFile() != null)) {
return loc.getSourceFile().toString();
} else {
return "UNKNOWN";
}
} else {
return "UNKNOWN_KEY{" + key + "}";
}
}
}