in modules/asc/src/java/macromedia/asc/embedding/LintEvaluator.java [699:906]
public Value evaluate( Context cx, SetExpressionNode node )
{
if (first_pass)
{
return node.args.evaluate(cx,this);
}
Slot slot = null;
if( node.ref != null )
{
slot = node.ref.getSlot(cx,GET_TOKEN);
// special case for looking up a value of a class. ConstantEvaluator
// doesn't recognize direct Class references outside of the global scope, so
// it fails to set the ref's base correctly. It has to do this because when
// the function is called, its possible it will be called from a context where
// the global class definition has been superceeded by a local definition.
// This is pretty unlikely, however, and messes up the undeclared property reference
// detection. If the base of this expression (appears) to be the global definition for
// a class, temporarily reset the ref's base and use that definition.
TypeValue baseType = baseType_context.last();
if (baseType != null && "Class".equals(baseType.name.toString()))
{
ReferenceValue baseRef = baseRef_context.last();
if (baseRef != null)
{
ObjectValue realBase = (ObjectValue)(baseRef.getValue(cx));
ObjectValue oldBase = node.ref.getBase();
node.ref.setBase(realBase);
slot = node.ref.getSlot(cx,GET_TOKEN);
node.ref.setBase(oldBase);
}
}
// The last ditch, for handling Inteface base types. If there's a base type, see if its defined in its prototype.
// This definition is not good enough for code generation, but its good enough for a warning. Its pretty unlikely
// that the definition is superceeded at runtime.
if (slot == null && baseType != null && baseType.prototype != null && node.ref.name != null)
{
slot = getSlot(baseType.prototype, cx, node, SET_TOKEN);
}
//TypeValue* dt = node->ref->getType(cx); // this uses use-definition trees, rather than the slot's def. Assume slot's def for warnings
int base_index = node.ref.getScopeIndex(SET_TOKEN);
int slot_index = node.ref.getSlotIndex(SET_TOKEN);
boolean is_globalref = base_index == 0;
boolean is_dotref = base_index == -2;
boolean is_unbound_lexref = base_index == -1;
boolean is_unbound_dotref = is_dotref && slot_index < 0;
boolean is_unbound_globalref = is_globalref && slot_index < 0;
boolean is_unbound_ref = is_unbound_dotref || is_unbound_lexref || is_unbound_globalref;
if (slot != null && !(node.expr instanceof QualifiedIdentifierNode))
{
//if it's a qualified identifier node, then it's a member/static
//variable on a class that is being initialized, like this:
//public var memberVar:String = "hi";
//this case should not have a warning!
checkDeprecatedSlot(cx, node.expr, node.ref, slot);
}
// special case to avoid warning on access to a Class's prototype property. This
// property can't be expressed in global.as because you can't both declare a class
// and declare it to be an instance of the Class class.
if (baseType != null && "Class".equals(baseType.name.toString()) && "prototype".equals(node.ref.name))
{
}
else if (slot != null && slot.getType().getTypeValue() == cx.uintType() &&
node.args != null && node.args.items.size() == 1 && node.args.items.get(0) instanceof LiteralNumberNode)
{
LiteralNumberNode ln = (LiteralNumberNode)(node.args.items.get(0));
if (ln.numericValue.doubleValue() < 0)
warning(node.getPosition(), cx.input, kWarning_NegativeUintLiteral);
}
else if ( slot == null && is_unbound_ref)
{
int pos = (node.expr != null ? node.expr.getPosition() : node.getPosition());
boolean unsupported = false;
if (baseType == types[kDateType] || baseType == cx.regExpType() ||
(types[kErrorType] != null && types[kErrorType].includes(cx,baseType))) // these types are dynamic for backwards compatability, so ! doesn't catch this. Its unlikely anyone is adding dynamic props to them
{
warning(node.pos(), cx.input, kWarning_BadES3TypeProp, node.ref.name, baseType.name.name);
unsupported = true;
}
else
{
Map<TypeValue,Integer> search = unsupportedPropsMap.get(node.ref.name);
if (search != null && !search.isEmpty())
{
TypeValue searchType = baseType_context.last(); // todo: why is this more reliable than node->ref->base
// if this is an attempt to access a static member of a class, switch searchType to the class's type
// This is necessary to allow lookup in the unsupportedMethodsMap table.
if (searchType != null && "Class".equals(searchType.name.toString()))
{
ReferenceValue br = baseRef_context.back();
Slot s = (br != null ? br.getSlot(cx,GET_TOKEN) : null);
// c++ variant accesses union member typValue directly, java stores value in objValue
TypeValue t = (s != null && s.getObjectValue() instanceof TypeValue) ? (TypeValue)(s.getObjectValue()) : null;
searchType = (t != null) ? t : searchType;
}
for(TypeValue type : search.keySet())
{
if (type != null && type.includes(cx,searchType))
{
unsupported = true;
warning(pos, cx.input, kWarning_DepricatedPropertyError, node.ref.name,
warningConstantsMap.get(search.get(type)));
}
}
}
}
if (unsupported == false && baseType != null ) // check for unsupported event handlers (StyleSheet.onLoad = new function() ... )
{
Map<TypeValue,Integer> search = unsupportedEventsMap.get(node.ref.name);
if (search != null && ! search.isEmpty()) // it matches a former auto-registered event handler name
{
ObjectValue scope = cx.scope();
if (baseType != null) // !!@todo: check that this dynamic var wasn't seen in an addEventListener call during first_pass
{
TypeValue searchType = baseType_context.last(); // todo: why is this more reliable than node->ref->base
// if this is an attempt to access a static member of a class, switch searchType to the class's type
// This is necessary to allow lookup in the unsupportedMethodsMap table.
if (searchType != null && "Class".equals(searchType.name.toString()))
{
ReferenceValue br = baseRef_context.back();
Slot s = (br != null ? br.getSlot(cx,GET_TOKEN) : null);
// c++ variant accesses union member typValue directly, java stores value in objValue
TypeValue t = (s != null && s.getObjectValue() instanceof TypeValue) ? (TypeValue)(s.getObjectValue()) : null;
searchType = (t != null) ? t : searchType;
}
for(TypeValue type : search.keySet())
{
if (type != null && type.includes(cx,searchType)) // it's defining Type matches one of the warning cases
{
warning(pos, cx.input, kWarning_DepricatedEventHandlerError, warningConstantsMap.get(search.get(type)));
unsupported = true;
}
}
}
}
}
ObjectValue base = node.ref.getBase();
if ((baseType != null && baseType != cx.voidType() && baseType != cx.nullType())
&& ((base != null && base.isFinal() && !base.isDynamic())
|| cx.doubleType().includes(cx, baseType)
|| cx.numberType() == baseType
|| (cx.statics.es4_numerics && cx.decimalType() == baseType)
|| cx.stringType() == baseType
|| cx.booleanType() == baseType
|| types[kMathType] == baseType))
{
warning(node.getPosition(), cx.input, kWarning_ClassIsSealed, getSimpleTypeName(baseType));
}
}
else if (baseType == types[kTextFieldType] && "text".equals(node.ref.name))
{
// look for " member.text += "some text" type syntax. The compiler will have already converted this to
// "member.text = member.text + "some text" by now
Node arg1 = node.args.items.get(0);
if (arg1 instanceof BinaryExpressionNode)
{
MemberExpressionNode membArg = (((BinaryExpressionNode)arg1).lhs instanceof MemberExpressionNode) ?
(MemberExpressionNode)(((BinaryExpressionNode)arg1).lhs) :
null;
if (membArg != null)
{
MemberExpressionNode membArgBase = (membArg.base instanceof MemberExpressionNode) ? (MemberExpressionNode)(membArg.base) : null;
ReferenceValue br = baseRef_context.back();
if (membArgBase != null && membArgBase.ref != null && br != null && br.slot == membArgBase.ref.slot)
warning(node.getPosition(), cx.input, kWarning_SlowTextFieldAddition);
}
}
}
}
else
{
node.expr.evaluate(cx,this);
}
Value result = node.args.evaluate(cx,this);
if (result == cx.nullType() && slot != null)
{
TypeValue t = slot.getType().getTypeValue();
TypeValue rt = (TypeValue)result;
if ((t != null) && (t.isNumeric(cx) || t == cx.booleanType()))
warning(node.args.getPosition(), cx.input, kWarning_BadNullAssignment, t.name.toString());
}
else if (slot != null && slot.getType().getTypeValue() == cx.booleanType() && result instanceof TypeValue &&
result != cx.booleanType() && result != cx.noType() && result != cx.objectType())
{
TypeValue rt = (TypeValue)result;
warning(node.args.getPosition(), cx.input, kWarning_BadBoolAssignment, rt.name.toString());
}
return result;
}