Files
codeql/java/ql/src/utils/flowtestcasegenerator/FlowTestCaseUtils.qll
Joe Farebrother a9f1436930 Test generator fixes
- Revert previous change to constructor return values; as constructors are supposed to be modeled using Argument[-1] rather than ReturnValue
- Fix generation of ambiguous calls when one of the conflicting methods is overridden
2023-02-17 15:30:06 +00:00

135 lines
4.0 KiB
Plaintext

/**
* Utility predicates useful for test generation.
*/
import java
private import semmle.code.java.dataflow.internal.DataFlowUtil
private import semmle.code.java.dataflow.FlowSummary
private import FlowTestCase
/**
* Returns `t`'s outermost enclosing type, in raw form (i.e. generic types are given without generic parameters, and type variables are replaced by their bounds).
*/
Type getRootSourceDeclaration(Type t) {
if t instanceof RefType
then result = getRootType(replaceTypeVariable(t)).(RefType).getSourceDeclaration()
else result = t
}
/**
* Holds if type `t` does not clash with another type we want to import that has the same base name.
*/
predicate isImportable(Type t) {
t = any(TestCase tc).getADesiredImport() and
t =
unique(Type sharesBaseName |
sharesBaseName = any(TestCase tc).getADesiredImport() and
sharesBaseName.getName() = t.getName()
|
sharesBaseName
)
}
/**
* Returns `t`'s first upper bound if `t` is a type variable; otherwise returns `t`.
*/
RefType replaceTypeVariable(RefType t) {
if t instanceof TypeVariable
then result = replaceTypeVariable(t.(TypeVariable).getFirstUpperBoundType())
else result = t
}
/**
* Returns a zero value of primitive type `t`.
*/
string getZero(PrimitiveType t) {
t.hasName("float") and result = "0.0f"
or
t.hasName("double") and result = "0.0"
or
t.hasName("int") and result = "0"
or
t.hasName("boolean") and result = "false"
or
t.hasName("short") and result = "(short)0"
or
t.hasName("byte") and result = "(byte)0"
or
t.hasName("char") and result = "'\\0'"
or
t.hasName("long") and result = "0L"
}
/**
* Holds if `c` may require disambiguation from an overload with the same argument count.
*/
predicate mayBeAmbiguous(Callable c) {
exists(Callable other, Callable override, string package, string type, string name |
override = [c, c.(Method).getASourceOverriddenMethod*()] and
override.hasQualifiedName(package, type, name) and
other.hasQualifiedName(package, type, name) and
other.getNumberOfParameters() = override.getNumberOfParameters() and
other != override
)
or
c.isVarargs()
}
/**
* Returns the outermost type enclosing type `t` (which may be `t` itself).
*/
Type getRootType(Type t) {
if t instanceof NestedType
then result = getRootType(t.(NestedType).getEnclosingType())
else
if t instanceof Array
then result = getRootType(t.(Array).getElementType())
else result = t
}
/**
* Returns a printable name for type `t`, stripped of generics and, if a type variable,
* replaced by its bound. Usually this is a short name, but it may be package-qualified
* if we cannot import it due to a name clash.
*/
string getShortNameIfPossible(Type t) {
if t instanceof Array
then result = getShortNameIfPossible(t.(Array).getComponentType()) + "[]"
else (
if t instanceof RefType
then
getRootSourceDeclaration(t) = any(TestCase tc).getADesiredImport() and
exists(RefType replaced, string nestedName |
replaced = replaceTypeVariable(t).getSourceDeclaration() and
nestedName = replaced.nestedName().replaceAll("$", ".")
|
if isImportable(getRootSourceDeclaration(t))
then result = nestedName
else result = replaced.getPackage().getName() + "." + nestedName
)
else result = t.getName()
)
}
/**
* Gets a string that specifies summary component `c` in a summary specification CSV row.
*/
string getComponentSpec(SummaryComponent c) {
exists(Content content |
c = SummaryComponent::content(content) and
(
content instanceof ArrayContent and result = "ArrayElement"
or
content instanceof MapValueContent and result = "MapValue"
or
content instanceof MapKeyContent and result = "MapKey"
or
content instanceof CollectionContent and result = "Element"
or
result = "Field[" + content.(FieldContent).getField().getQualifiedName() + "]"
or
result = "SyntheticField[" + content.(SyntheticFieldContent).getField() + "]"
)
)
}