use of org.checkerframework.dataflow.analysis.FlowExpressions.ClassName in project checker-framework by typetools.
the class CFAbstractStore method insertValue.
/**
* Add the abstract value {@code value} for the expression {@code r} (correctly deciding where
* to store the information depending on the type of the expression {@code r}).
*
* <p>This method does not take care of removing other information that might be influenced by
* changes to certain parts of the state.
*
* <p>If there is already a value {@code v} present for {@code r}, then the stronger of the new
* and old value are taken (according to the lattice). Note that this happens per hierarchy, and
* if the store already contains information about a hierarchy for which {@code value} does not
* contain information, then that information is preserved.
*/
public void insertValue(FlowExpressions.Receiver r, @Nullable V value) {
if (value == null) {
// top and top is also the default value.
return;
}
if (r.containsUnknown()) {
// Expressions containing unknown expressions are not stored.
return;
}
if (r instanceof FlowExpressions.LocalVariable) {
FlowExpressions.LocalVariable localVar = (FlowExpressions.LocalVariable) r;
V oldValue = localVariableValues.get(localVar);
V newValue = value.mostSpecific(oldValue, null);
if (newValue != null) {
localVariableValues.put(localVar, newValue);
}
} else if (r instanceof FlowExpressions.FieldAccess) {
FlowExpressions.FieldAccess fieldAcc = (FlowExpressions.FieldAccess) r;
// Only store information about final fields (where the receiver is
// also fixed) if concurrent semantics are enabled.
boolean isMonotonic = isMonotonicUpdate(fieldAcc, value);
if (sequentialSemantics || isMonotonic || fieldAcc.isUnmodifiableByOtherCode()) {
V oldValue = fieldValues.get(fieldAcc);
V newValue = value.mostSpecific(oldValue, null);
if (newValue != null) {
fieldValues.put(fieldAcc, newValue);
}
}
} else if (r instanceof FlowExpressions.MethodCall) {
FlowExpressions.MethodCall method = (FlowExpressions.MethodCall) r;
// Don't store any information if concurrent semantics are enabled.
if (sequentialSemantics) {
V oldValue = methodValues.get(method);
V newValue = value.mostSpecific(oldValue, null);
if (newValue != null) {
methodValues.put(method, newValue);
}
}
} else if (r instanceof FlowExpressions.ArrayAccess) {
FlowExpressions.ArrayAccess arrayAccess = (ArrayAccess) r;
if (sequentialSemantics) {
V oldValue = arrayValues.get(arrayAccess);
V newValue = value.mostSpecific(oldValue, null);
if (newValue != null) {
arrayValues.put(arrayAccess, newValue);
}
}
} else if (r instanceof FlowExpressions.ThisReference) {
FlowExpressions.ThisReference thisRef = (FlowExpressions.ThisReference) r;
if (sequentialSemantics || thisRef.isUnmodifiableByOtherCode()) {
V oldValue = thisValue;
V newValue = value.mostSpecific(oldValue, null);
if (newValue != null) {
thisValue = newValue;
}
}
} else if (r instanceof FlowExpressions.ClassName) {
FlowExpressions.ClassName className = (FlowExpressions.ClassName) r;
if (sequentialSemantics || className.isUnmodifiableByOtherCode()) {
V oldValue = classValues.get(className);
V newValue = value.mostSpecific(oldValue, null);
if (newValue != null) {
classValues.put(className, newValue);
}
}
} else {
// No other types of expressions need to be stored.
}
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.ClassName in project checker-framework by typetools.
the class FlowExpressionParseUtil method parseMemberSelect.
private static Receiver parseMemberSelect(String s, ProcessingEnvironment env, FlowExpressionContext context, TreePath path) throws FlowExpressionParseException {
Pair<String, String> select = parseMemberSelect(s);
assert select != null : "isMemberSelect must be called first";
Receiver receiver;
String memberSelected;
Resolver resolver = new Resolver(env);
// Attempt to match a package and class name first.
Pair<ClassName, String> classAndRemainingString = matchPackageAndClassNameWithinExpression(s, resolver, path);
if (classAndRemainingString != null) {
receiver = classAndRemainingString.first;
memberSelected = classAndRemainingString.second;
if (memberSelected == null) {
throw constructParserException(s, "a class cannot terminate a flow expression string");
}
} else {
String receiverString = select.first;
memberSelected = select.second;
receiver = parseHelper(receiverString, context, path);
}
if (memberSelected.equals("class")) {
if (receiver instanceof FlowExpressions.ClassName && !context.parsingMember) {
return receiver;
} else {
throw constructParserException(s, "class is not a legal identifier");
}
}
// Parse the rest, with a new receiver.
FlowExpressionContext newContext = context.copyChangeToParsingMemberOfReceiver(receiver);
return parseHelper(memberSelected, newContext, path);
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.ClassName in project checker-framework by typetools.
the class FlowExpressionParseUtil method matchPackageAndClassNameWithinExpression.
/**
* Matches a substring of {@code expression} to a package and class name (starting from the
* beginning of the string).
*
* @param expression the expression string that may start with a package and class name
* @param resolver the {@code Resolver} for the current processing environment
* @param path the tree path to the local scope
* @return {@code null} if the expression string did not start with a package name; otherwise a
* {@code Pair} containing the {@code ClassName} for the matched class, and the remaining
* substring of the expression (possibly null) after the package and class name.
* @throws FlowExpressionParseException if the entire expression string matches a package name
* (but no class name), or if a package name was matched but the class could not be found
* within the package (e.g., {@code "myExistingPackage.myNonExistentClass"}).
*/
private static Pair<ClassName, String> matchPackageAndClassNameWithinExpression(String expression, Resolver resolver, TreePath path) throws FlowExpressionParseException {
Pair<PackageSymbol, String> packageSymbolAndRemainingString = matchPackageNameWithinExpression(expression, resolver, path);
if (packageSymbolAndRemainingString == null) {
return null;
}
PackageSymbol packageSymbol = packageSymbolAndRemainingString.first;
String packageRemainingString = packageSymbolAndRemainingString.second;
Pair<String, String> select = parseMemberSelect(packageRemainingString);
String classNameString;
String remainingString;
if (select != null) {
classNameString = select.first;
remainingString = select.second;
} else {
classNameString = packageRemainingString;
remainingString = null;
}
ClassSymbol classSymbol;
try {
classSymbol = resolver.findClassInPackage(classNameString, packageSymbol, path);
} catch (Throwable t) {
throw constructParserException(expression, " findClassInPackage threw an exception when looking up class " + classNameString + " in package " + packageSymbol.toString(), t);
}
if (classSymbol == null) {
throw constructParserException(expression, "classSymbol==null when looking up class " + classNameString + " in package " + packageSymbol.toString());
}
TypeMirror classType = ElementUtils.getType(classSymbol);
if (classType == null) {
throw constructParserException(expression, "classType==null when looking for class symbol " + classSymbol);
}
return Pair.of(new ClassName(classType), remainingString);
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.ClassName in project checker-framework by typetools.
the class FlowExpressionParseUtil method parseIdentifier.
private static Receiver parseIdentifier(String s, ProcessingEnvironment env, TreePath path, FlowExpressionContext context) throws FlowExpressionParseException {
Resolver resolver = new Resolver(env);
if (!context.parsingMember && context.useLocalScope) {
// Attempt to match a local variable within the scope of the
// given path before attempting to match a field.
VariableElement varElem = resolver.findLocalVariableOrParameterOrField(s, path);
if (varElem != null) {
if (varElem.getKind() == ElementKind.FIELD) {
boolean isOriginalReceiver = context.receiver instanceof ThisReference;
return getReceiverField(s, context, isOriginalReceiver, varElem);
} else {
return new LocalVariable(varElem);
}
}
}
// field access
TypeMirror receiverType = context.receiver.getType();
boolean originalReceiver = true;
VariableElement fieldElem = null;
if (receiverType.getKind() == TypeKind.ARRAY && s.equals("length")) {
fieldElem = resolver.findField(s, receiverType, path);
}
// Search for field in each enclosing class.
while (receiverType.getKind() == TypeKind.DECLARED) {
fieldElem = resolver.findField(s, receiverType, path);
if (fieldElem != null) {
break;
}
receiverType = getTypeOfEnclosingClass((DeclaredType) receiverType);
originalReceiver = false;
}
if (fieldElem != null && fieldElem.getKind() == ElementKind.FIELD) {
return getReceiverField(s, context, originalReceiver, fieldElem);
}
// Class name
Element classElem = resolver.findClass(s, path);
TypeMirror classType = ElementUtils.getType(classElem);
if (classType != null) {
return new ClassName(classType);
}
throw constructParserException(s, "identifier not found");
}
use of org.checkerframework.dataflow.analysis.FlowExpressions.ClassName in project checker-framework by typetools.
the class FlowExpressionParseUtil method parseMethod.
private static Receiver parseMethod(String s, FlowExpressionContext context, TreePath path, ProcessingEnvironment env) throws FlowExpressionParseException {
Pair<Pair<String, String>, String> method = parseMethod(s);
if (method == null) {
return null;
}
String methodName = method.first.first;
// parse parameter list
String parameterList = method.first.second;
List<Receiver> parameters = ParameterListParser.parseParameterList(parameterList, true, context.copyAndUseOuterReceiver(), path);
// get types for parameters
List<TypeMirror> parameterTypes = new ArrayList<>();
for (Receiver p : parameters) {
parameterTypes.add(p.getType());
}
ExecutableElement methodElement = null;
try {
Element element = null;
// try to find the correct method
Resolver resolver = new Resolver(env);
TypeMirror receiverType = context.receiver.getType();
if (receiverType.getKind() == TypeKind.ARRAY) {
element = resolver.findMethod(methodName, receiverType, path, parameterTypes);
}
// Search for method in each enclosing class.
while (receiverType.getKind() == TypeKind.DECLARED) {
element = resolver.findMethod(methodName, receiverType, path, parameterTypes);
if (element.getKind() == ElementKind.METHOD) {
break;
}
receiverType = getTypeOfEnclosingClass((DeclaredType) receiverType);
}
if (element == null) {
throw constructParserException(s, "element==null");
}
if (element.getKind() != ElementKind.METHOD) {
throw constructParserException(s, "element.getKind()==" + element.getKind());
}
methodElement = (ExecutableElement) element;
for (int i = 0; i < parameters.size(); i++) {
VariableElement formal = methodElement.getParameters().get(i);
TypeMirror formalType = formal.asType();
Receiver actual = parameters.get(i);
TypeMirror actualType = actual.getType();
// boxing necessary
if (TypesUtils.isBoxedPrimitive(formalType) && TypesUtils.isPrimitive(actualType)) {
MethodSymbol valueOfMethod = TreeBuilder.getValueOfMethod(env, formalType);
List<Receiver> p = new ArrayList<>();
p.add(actual);
Receiver boxedParam = new MethodCall(formalType, valueOfMethod, new ClassName(formalType), p);
parameters.set(i, boxedParam);
}
}
} catch (Throwable t) {
throw constructParserException(s, t);
}
assert methodElement != null;
/*if (!PurityUtils.isDeterministic(context.checkerContext.getAnnotationProvider(),
methodElement)) {
throw new FlowExpressionParseException(Result.failure(
"flowexpr.method.not.deterministic",
methodElement.getSimpleName()));
}*/
if (ElementUtils.isStatic(methodElement)) {
Element classElem = methodElement.getEnclosingElement();
Receiver staticClassReceiver = new ClassName(ElementUtils.getType(classElem));
return new MethodCall(ElementUtils.getType(methodElement), methodElement, staticClassReceiver, parameters);
} else {
if (context.receiver instanceof ClassName) {
throw constructParserException(s, "a non-static method call cannot have a class name as a receiver.");
}
TypeMirror methodType = TypesUtils.substituteMethodReturnType(methodElement, context.receiver.getType(), env);
return new MethodCall(methodType, methodElement, context.receiver, parameters);
}
}
Aggregations