proguard.evaluation.value.ParticularReferenceValue Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of proguard-core Show documentation
Show all versions of proguard-core Show documentation
ProGuardCORE is a free library to read, analyze, modify, and write Java class files.
/*
* ProGuardCORE -- library to process Java bytecode.
*
* Copyright (c) 2002-2021 Guardsquare NV
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package proguard.evaluation.value;
import proguard.classfile.AccessConstants;
import proguard.classfile.Clazz;
import proguard.classfile.util.ClassUtil;
import java.util.Objects;
/**
* This {@link ParticularReferenceValue} represents a particular reference value, i.e. a reference with an associated value.
* E.g., a String with the value "HelloWorld".
*
* @author Dennis Titze
*/
public class ParticularReferenceValue extends IdentifiedReferenceValue
{
// The actual value of the object.
private final Object value;
/**
* Create a new Instance with the given type, the class it is referenced in, and its actual value.
*/
public ParticularReferenceValue(String type,
Clazz referencedClass,
ValueFactory valueFactory,
int referenceID,
Object value)
{
// We store the unique ID to keep track of the same value (independent of casting and generalizations) on stack and vars.
// This ID is needed, since the generalization and casting might create new instances, and we need to see that these were in fact the ones we need to replace.
super(type, referencedClass, false, true, valueFactory, referenceID);
this.value = value;
// Sanity checks.
if (value != null && !type.equals(ClassUtil.internalType(value.getClass().getCanonicalName())))
{
throw new RuntimeException("Type does not match type of the value (" + ClassUtil.internalType(value.getClass().getCanonicalName()) + " - " + type + ")");
}
if (type == null)
{
throw new RuntimeException("Type must not be null");
}
}
// Implementations for ReferenceValue.
@Override
public Object value()
{
return value;
}
// Implementations for TypedReferenceValue.
@Override
public boolean isParticular()
{
return true;
}
@Override
public int isNull()
{
return value == null ? ALWAYS : NEVER;
}
@Override
public int instanceOf(String otherType, Clazz otherReferencedClass)
{
// If the value extends the type, we're sure (unless it may be null).
// Otherwise, if the value type is final, it can never be an instance.
// Also, if the types are not interfaces and not in the same hierarchy,
// the value can never be an instance.
if (referencedClass == null ||
otherReferencedClass == null)
{
return MAYBE;
}
else
{
if (referencedClass.extendsOrImplements(otherReferencedClass))
{
return ALWAYS;
}
else
{
if ((referencedClass.getAccessFlags() & AccessConstants.FINAL) != 0)
{
return NEVER;
}
if ((referencedClass.getAccessFlags() & AccessConstants.INTERFACE) == 0 &&
(otherReferencedClass.getAccessFlags() & AccessConstants.INTERFACE) == 0 &&
!otherReferencedClass.extendsOrImplements(referencedClass))
{
return NEVER;
}
return MAYBE;
}
}
}
@Override
public ReferenceValue cast(String type, Clazz referencedClass, ValueFactory valueFactory, boolean alwaysCast)
{
// Just return this value if it's the same type.
// Also return this value if it is null or more specific.
if (!alwaysCast &&
(this.type == null ||
instanceOf(type, referencedClass) == ALWAYS))
{
return this;
}
else if (this.type != null &&
this.type.equals(type))
{
return this;
}
if (instanceOf(type, referencedClass) == ALWAYS)
{
return valueFactory.createReferenceValue(type,
referencedClass,
true,
true,
value);
}
// not instance of this. Returning unknown.
return valueFactory.createReferenceValue(type,
referencedClass,
true,
true);
}
@Override
public ReferenceValue generalize(ReferenceValue other)
{
return other.generalize(this);
}
@Override
public ReferenceValue generalize(ParticularReferenceValue other)
{
if (this.equal(other) == ALWAYS)
{
return other;
}
return super.generalize((IdentifiedReferenceValue) other);
}
@Override
public int hashCode()
{
return this.getClass().hashCode() ^
(value == null ? 1 : value.hashCode());
}
@Override
public boolean equals(Object object)
{
return super.equals(object) &&
object instanceof ParticularReferenceValue &&
Objects.equals(value, ((ParticularReferenceValue) object).value);
}
@Override
public int equal(ReferenceValue other)
{
if (this == other)
{
return ALWAYS;
}
if (super.equal(other) == NEVER)
{
return NEVER;
}
if (getClass() != other.getClass())
{
return MAYBE;
}
// now, the type and class equals.
if ((value == null && other.value() == null)
||
(value != null && value.equals(other.value())))
{
return ALWAYS;
}
return NEVER;
}
@Override
public String toString()
{
return super.toString() + "(" + (value == null ? "null" : value.toString()) + ")";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy