blob: f7f06d77e444307f7f76106acdf0947fe9d7d0d6 [file] [log] [blame]
// Copyright (C) 2016 The Android Open Source Project
//
// 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 analysis
import (
"fmt"
"strings"
"android.googlesource.com/platform/tools/gpu/api/semantic"
)
// Value interface compliance checks.
var (
_ = Value(&ReferenceValue{})
_ = fieldHolder(&ReferenceValue{})
)
// ReferenceValue is an implementation of Value that represents all the possible
// references of a reference value type.
// As references are an indirection, this value only holds the set of references
// not the set of referenced values. The actual referenced values are held by
// the scope.
// ReferenceValues uses *semantic.Create as the reference handles.
type ReferenceValue struct {
// The reference type.
Ty semantic.Type
// Unknown is the unknown value of the referenced type.
Unknown Value
// Assignments is the set of all assignments made to this value.
Assignments map[*semantic.Create]struct{}
}
func (v *ReferenceValue) String() string {
if len(v.Assignments) == 0 {
return "<nil>"
}
pointers := make([]string, 0, len(v.Assignments))
for a := range v.Assignments {
pointers = append(pointers, fmt.Sprintf("%p", a))
}
return "ref!" + strings.Join(pointers, ", ")
}
// Print returns a textual representation of the value.
func (v *ReferenceValue) Print(results *Results) string {
if len(v.Assignments) == 0 {
return "<nil>"
}
values := make([]Value, 0, len(v.Assignments))
for a := range v.Assignments {
values = append(values, results.Instances[a])
}
return "ref!" + unionOf(values...).Print(results)
}
// Type returns the semantic reference type of the value.
func (v *ReferenceValue) Type() semantic.Type { return v.Ty }
// Equivalent returns true iff v and o are equivalent.
// Unlike Equals() which returns the possibility of two values being equal,
// Equivalent() returns true iff the set of possible field values are exactly
// equal.
// o must be of type *ReferenceValue.
func (v *ReferenceValue) Equivalent(o Value) bool {
a, b := v, o.(*ReferenceValue)
if len(a.Assignments) != len(b.Assignments) {
return false
}
for c := range a.Assignments {
if _, ok := b.Assignments[c]; !ok {
return false
}
}
for c := range b.Assignments {
if _, ok := a.Assignments[c]; !ok {
return false
}
}
return true
}
// Equals returns the possibility of the reference value v being equal to o.
// o must be of type *ReferenceValue.
func (v *ReferenceValue) Equals(o Value) Possibility {
if v == o && v.Valid() {
return True
}
a, b := v, o.(*ReferenceValue)
if len(a.Assignments) == len(b.Assignments) {
switch len(a.Assignments) {
case 0:
return True
case 1:
for s := range a.Assignments {
if _, ok := b.Assignments[s]; ok {
return True
}
}
}
}
return Maybe // There's always null == null
}
// Valid returns true.
func (v *ReferenceValue) Valid() bool {
return true
}
// Union (∪) returns the reference value with all the assignments of v and o.
// o must be of type *ReferenceValue.
func (v *ReferenceValue) Union(o Value) Value {
a, b := v, o.(*ReferenceValue)
out := a.Clone().(*ReferenceValue)
for s := range b.Assignments {
out.Assignments[s] = struct{}{}
}
return out
}
// Intersect (∩) returns the reference value the assignments that are found in
// both v and o.
// o must be of type *ReferenceValue.
func (v *ReferenceValue) Intersect(o Value) Value {
a, b := v, o.(*ReferenceValue)
out := a.Clone().(*ReferenceValue)
for s := range a.Assignments {
if _, ok := b.Assignments[s]; !ok {
delete(out.Assignments, s)
}
}
return out
}
// Difference (\) returns the reference value with assignments that are found in
// v but not found in o.
// o must be of type *ReferenceValue.
func (v *ReferenceValue) Difference(o Value) Value {
a, b := v, o.(*ReferenceValue)
out := &ReferenceValue{Ty: v.Ty, Unknown: v.Unknown, Assignments: map[*semantic.Create]struct{}{}}
for s := range a.Assignments {
if _, ok := b.Assignments[s]; !ok {
out.Assignments[s] = struct{}{}
}
}
return out
}
// Clone returns a copy of v with a unique pointer.
func (v *ReferenceValue) Clone() Value {
out := &ReferenceValue{Ty: v.Ty, Unknown: v.Unknown, Assignments: map[*semantic.Create]struct{}{}}
for s := range v.Assignments {
out.Assignments[s] = struct{}{}
}
return out
}
// field returns the union of all the fields with the specfied name across all
// assignments to v.
func (v *ReferenceValue) field(s *scope, name string) Value {
candidates := make([]Value, 0, len(v.Assignments))
for a := range v.Assignments {
field := s.getInstance(a).(fieldHolder).field(s, name)
candidates = append(candidates, field)
}
if len(candidates) == 0 {
return v.Unknown.(fieldHolder).field(s, name)
}
return unionOf(candidates...)
}
// setField calls setField across all assignments to v and updating the value
// in the scope's instances map.
func (v *ReferenceValue) setField(s *scope, name string, val Value) Value {
for a := range v.Assignments {
s.instances[a] = s.getInstance(a).(fieldHolder).setField(s, name, val)
}
return v
}