/* === This file is part of Jive JML dynamic program verifier ===
*
* Copyright 2012, Arvind S Raj <sraj[dot]arvind[at]gmail[dot]com>
*
* Jive JML dynamic program verifier is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* Jive JML Dynamic Program Verifier 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Jive JML Dynamic Program Verifier. If not, see
* <http://www.gnu.org/licenses/>.
*/
import java.io.*;
import java.lang.Math;
import java.util.ArrayList;
import java.util.HashMap;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.Type;
import org.jmlspecs.jir.JirExtractor;
import org.jmlspecs.jir.ast.JirAxiomClause;
import org.jmlspecs.jir.ast.JirConstraintClause;
import org.jmlspecs.jir.ast.JirClause;
import org.jmlspecs.jir.ast.JirExpression;
import org.jmlspecs.jir.ast.JirFieldSpec;
import org.jmlspecs.jir.ast.JirInDataGroupClause;
import org.jmlspecs.jir.ast.JirInitiallyClause;
import org.jmlspecs.jir.ast.JirInvariantForType;
import org.jmlspecs.jir.ast.JirLocalDeclaration;
import org.jmlspecs.jir.ast.JirMethodSpec;
import org.jmlspecs.jir.ast.JirRepresentsClause;
import org.jmlspecs.jir.ast.JirSpecCase;
import org.jmlspecs.jir.ast.JirSpecCaseBody;
import org.jmlspecs.jir.ast.JirTypeSpec;
import org.jmlspecs.jir.info.JirMethodInfo;
import org.jmlspecs.jir.ast.JirNodeInfo;
import org.jmlspecs.jir.info.JirTypeInfo;
public class JmlExtractor {
private String classFileName;
private JirTypeInfo typeInfo;
public final static int typeBinarySignature = 1;
public final static int typeMethodName = 2;
public final static int typeForallVars = 3;
public final static int typeOldVars = 4;
public final static int typeImpliedSpecCase = 5;
public final static int typeSpecCase = 6;
public JmlExtractor(String fileName) throws IOException, InvalidClassFile, JirSpecificationNotFound {
classFileName = fileName;
JirExtractor extractor = new JirExtractor();
try {
typeInfo = extractor.getSpec(classFileName);
}
catch (ArrayIndexOutOfBoundsException e) {
throw new InvalidClassFile(classFileName);
}
if(typeInfo == null) {
throw new JirSpecificationNotFound(classFileName);
}
}
public HashMap getAllFieldSpec() {
return typeInfo.getFields();
}
public HashMap getAllMethodSpec() {
return typeInfo.getMethods();
}
public JirTypeSpec getAllTypeSpec() {
return typeInfo.getTypeSpec();
}
public String getClassFileName() {
return classFileName;
}
public Expression getExpression(JirClause jirClause) {
if(jirClause.getDescriptor() == JirRepresentsClause.DESCRIPTOR) {
return (Expression)((JirRepresentsClause)jirClause).getStoreRef().getExpression();
}
return (Expression)jirClause.getExpr().getExpression();
}
public Expression getExpression(JirExpression jirExpression) {
return (Expression)jirExpression.getExpression();
}
public HashMap<Integer, ArrayList<Expression>> getExpression(JirFieldSpec fieldSpec) {
ArrayList<Expression> expressionArray = new ArrayList<Expression> ();
ArrayList<JirInDataGroupClause> inDataGroupClauses = fieldSpec.getInDataGroupClauses();
ArrayList<JirExpression> inDataGroupJirExpressions;
for(JirInDataGroupClause inDataGroupClause: inDataGroupClauses) {
inDataGroupJirExpressions = inDataGroupClause.getGroupNames();
for(JirExpression inDataGroupJirExpression: inDataGroupJirExpressions) {
expressionArray.add(getExpression(inDataGroupJirExpression));
}
}
HashMap<Integer, ArrayList<Expression>> expressionMap = new HashMap<Integer, ArrayList<Expression>> ();
expressionMap.put(JirInDataGroupClause.DESCRIPTOR, expressionArray);
return expressionMap;
}
public ArrayList<Expression> getExpression(JirLocalDeclaration localDeclaration) {
ArrayList<Expression> expressionList = new ArrayList<Expression>();
ArrayList<JirExpression> jirExpressions = localDeclaration.getInitializations();
for(JirExpression jirExpression: jirExpressions) {
expressionList.add(getExpression(jirExpression));
}
return expressionList;
}
public ArrayList<HashMap<Integer, Expression>> getExpression(JirMethodSpec methodSpec, int typeSpecCase) {
ArrayList<HashMap<Integer, Expression>> expressionList = new ArrayList<HashMap<Integer, Expression>> ();
ArrayList<JirSpecCase> specCaseList;
if(typeSpecCase == JmlExtractor.typeImpliedSpecCase) {
specCaseList = methodSpec.getImpliedSpecCases();
}
else {
specCaseList = methodSpec.getSpecCases();
}
for(JirSpecCase specCase: specCaseList) {
expressionList.add(getExpression(specCase));
}
return expressionList;
}
public HashMap<Integer, Expression> getExpression(JirSpecCase specCase) {
HashMap<Integer, Expression> expressionList = new HashMap<Integer, Expression> ();
for(JirClause jirClause: (ArrayList<JirClause>)specCase.getBody().getRequiresClauses()) {
expressionList.put(jirClause.getDescriptor(), getExpression(jirClause));
}
for(JirClause jirClause: (ArrayList<JirClause>)specCase.getBody().getRest()) {
expressionList.put(jirClause.getDescriptor(), getExpression(jirClause));
}
return expressionList;
}
public HashMap<Integer, ArrayList<Expression>> getExpression(JirTypeSpec typeSpec) {
ArrayList<Expression> expressionArray = new ArrayList<Expression>();
HashMap<Integer, ArrayList<Expression>> typeSpecExpr = new HashMap<Integer, ArrayList<Expression>> ();
for(JirAxiomClause axiomClause: (ArrayList<JirAxiomClause>)typeSpec.getAxiomClauses()) {
expressionArray.add(getExpression(axiomClause));
}
typeSpecExpr.put(JirAxiomClause.DESCRIPTOR, expressionArray);
expressionArray = new ArrayList<Expression>();
for(JirConstraintClause constraintClause: (ArrayList<JirConstraintClause>)typeSpec.getConstraintClauses()) {
expressionArray.add(getExpression(constraintClause));
}
typeSpecExpr.put(JirConstraintClause.DESCRIPTOR, expressionArray);
expressionArray = new ArrayList<Expression>();
for(JirInitiallyClause initiallyClause: (ArrayList<JirInitiallyClause>)typeSpec.getInitiallyClauses()) {
expressionArray.add(getExpression(initiallyClause));
}
typeSpecExpr.put(JirInitiallyClause.DESCRIPTOR, expressionArray);
expressionArray = new ArrayList<Expression>();
for(JirInvariantForType invariantClause: (ArrayList<JirInvariantForType>)typeSpec.getInvariantClauses()) {
expressionArray.add(getExpression(invariantClause));
}
typeSpecExpr.put(JirInvariantForType.DESCRIPTOR, expressionArray);
expressionArray = new ArrayList<Expression>();
for(JirRepresentsClause representsClause: (ArrayList<JirRepresentsClause>)typeSpec.getRepresentsClauses()) {
expressionArray.add(getExpression(representsClause));
}
typeSpecExpr.put(JirRepresentsClause.DESCRIPTOR, expressionArray);
expressionArray = new ArrayList<Expression>();
return typeSpecExpr;
}
protected String getMethodBinarySignature(HashMap<String, JirMethodInfo> possibleMethodInfos, int lineNumber) {
String methodSignature = null;
JirMethodSpec methodSpec = null;
JirNodeInfo nodeInfo = null;
int currentMinDifference = 0;
for(String methodInfoKey: possibleMethodInfos.keySet()) {
if(nodeInfo == null) {
methodSpec = possibleMethodInfos.get(methodInfoKey).getMethodSpec();
if(methodSpec != null) {
nodeInfo = methodSpec.getInfo();
methodSignature = methodInfoKey;
currentMinDifference = Math.abs(lineNumber - nodeInfo.getEndLine());
}
}
else {
nodeInfo = possibleMethodInfos.get(methodInfoKey).getMethodSpec().getInfo();
if((nodeInfo.getEndLine() <= lineNumber) && (Math.abs(lineNumber - nodeInfo.getEndLine()) < currentMinDifference)){
methodSignature = methodInfoKey;
currentMinDifference = Math.abs(lineNumber - nodeInfo.getEndLine());
}
}
}
return methodSignature;
}
public JirMethodSpec getMethodSpec(String methodAttribute, int methodAttributeType, int lineNumber) throws JirMethodSpecNotFound {
String methodBinarySignature = null;
JirMethodSpec methodSpec = null;
if(methodAttributeType == typeBinarySignature) {
methodBinarySignature = methodAttribute;
}
else {
HashMap<String, JirMethodInfo> possibleMethodInfos = getPossibleMethodInfos(methodAttribute.concat("("));
if(possibleMethodInfos.keySet().size() == 1) {
methodBinarySignature = possibleMethodInfos.keySet().iterator().next();
}
else {
methodBinarySignature = getMethodBinarySignature(possibleMethodInfos, lineNumber);
}
}
methodSpec = typeInfo.getMethodSpec(methodBinarySignature);
if(methodSpec == null) {
throw new JirMethodSpecNotFound(methodAttribute);
}
else {
return methodSpec;
}
}
protected HashMap<String, JirMethodInfo> getPossibleMethodInfos(String methodName) {
HashMap<String, JirMethodInfo> possibleMethodInfos = new HashMap<String, JirMethodInfo>();
HashMap<String, JirMethodInfo> methodInfos = typeInfo.getMethods();
for(String methodKey:methodInfos.keySet()) {
if(methodKey.startsWith(methodName)) {
possibleMethodInfos.put(methodKey, methodInfos.get(methodKey));
}
}
return possibleMethodInfos;
}
public JirTypeInfo getTypeInfo() {
return typeInfo;
}
public ArrayList<Expression> getVars(JirSpecCase specCase, int varType) {
ArrayList<Expression> expressionList = new ArrayList<Expression> ();
ArrayList<JirLocalDeclaration> vars;
if(varType == JmlExtractor.typeForallVars) {
vars = specCase.getBody().getForallVars();
}
else {
vars = specCase.getBody().getOldVars();
}
for(JirLocalDeclaration var: vars) {
for(Expression expression: getExpression(var)) {
expressionList.add(expression);
}
}
return expressionList;
}
};