package net.sourceforge.c4jplugin.internal.util;
import org.eclipse.core.resources.IResource;
import org.eclipse.jdt.core.IBuffer;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IOpenable;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.ToolFactory;
import org.eclipse.jdt.core.compiler.IScanner;
import org.eclipse.jdt.core.compiler.ITerminalSymbols;
import org.eclipse.jdt.core.compiler.InvalidInputException;
/**
* @author sascha
*
*/
/**
* @author sascha
*
*/
public class AnnotationUtil {
static private final String ANNOTATION_CONTRACT_REFERENCE = "ContractReference";
static public IResource getContractReference(IResource resource) {
try {
IJavaElement jelement = JavaCore.create(resource);
IType type = ContractReferenceUtil.getType(jelement);
if (type == null || !type.exists()) {
return null;
}
IBuffer buffer= null;
IOpenable openable= type.getOpenable();
if (openable instanceof ICompilationUnit) {
buffer= ((ICompilationUnit) openable).getBuffer();
} else if (openable instanceof IClassFile) {
buffer= ((IClassFile) openable).getBuffer();
}
if (buffer == null) return null;
ISourceRange sourceRange= type.getSourceRange();
ISourceRange nameRange= type.getNameRange();
if (sourceRange != null && nameRange != null) {
IScanner scanner= ToolFactory.createScanner(false, false, true, false);
scanner.setSource(buffer.getCharacters());
scanner.resetTo(sourceRange.getOffset(), nameRange.getOffset());
String arg = findAnnotation(scanner, ANNOTATION_CONTRACT_REFERENCE);
if (arg == null || arg.length() == 0) return null;
String[][] matches = type.resolveType(arg);
if (matches == null || matches.length > 1) {
// the contractValue cannot be resolved or is ambiguous
return null;
}
IType resolvedType = type.getJavaProject().findType(matches[0][0], matches[0][1]);
// check if the resolved resource has java errors
if (ContractReferenceUtil.hasJavaErrors(resolvedType)) {
return null;
}
// resolved type has no java errors
return resolvedType.getCompilationUnit().getCorrespondingResource();
}
}
catch (JavaModelException e) {}
catch (InvalidInputException e) {}
return null;
}
/**
* @param resource
* @return true if the contract status has changed
*/
static private String findAnnotation(IScanner scanner, String annotationName) throws InvalidInputException {
String simpleName= Signature.getSimpleName(annotationName);
StringBuffer buf= new StringBuffer();
int tok= scanner.getNextToken();
while (tok != ITerminalSymbols.TokenNameEOF) {
if (tok == ITerminalSymbols.TokenNameAT) {
buf.setLength(0);
tok= readName(scanner, buf);
String name= buf.toString();
if (name.equals(annotationName) || name.equals(simpleName) || name.endsWith('.' + simpleName)) {
StringBuffer bufArg = new StringBuffer();
bufArg.setLength(0);
readArgument(scanner, bufArg);
return bufArg.toString();
}
} else {
tok= scanner.getNextToken();
}
}
return null;
}
static private int readName(IScanner scanner, StringBuffer buf) throws InvalidInputException {
int tok= scanner.getNextToken();
while (tok == ITerminalSymbols.TokenNameIdentifier) {
buf.append(scanner.getCurrentTokenSource());
tok= scanner.getNextToken();
if (tok != ITerminalSymbols.TokenNameDOT) {
return tok;
}
buf.append('.');
tok= scanner.getNextToken();
}
return tok;
}
static private int readArgument(IScanner scanner, StringBuffer buf) throws InvalidInputException {
int tok = scanner.getNextToken();
while (tok != ITerminalSymbols.TokenNameRPAREN & tok != ITerminalSymbols.TokenNameEOF) {
if (tok == ITerminalSymbols.TokenNameStringLiteral) {
char[] literal = scanner.getCurrentTokenSource();
buf.append(literal, 1, literal.length-2);
return tok;
}
tok = scanner.getNextToken();
}
return tok;
}
}