ObserveUpstream imports all information from upstream dependencies. Specifically, it iterates over the direct imports of the passed pass's package, using the Facts mechanism to observe any InferredMap's that were computed by multi-package inference for that imported package. We copy the information
()
| 81 | // added to Mapping but not UpstreamMapping, then, on a call to Export, only the information |
| 82 | // present in Mapping but not UpstreamMapping is exported to ensure minimization of output. |
| 83 | func (e *Engine) ObserveUpstream() { |
| 84 | var facts []analysis.PackageFact |
| 85 | for _, packageFact := range e.pass.AllPackageFacts() { |
| 86 | // We only care about NilAway-related facts here. |
| 87 | if _, ok := packageFact.Fact.(*InferredMap); ok { |
| 88 | facts = append(facts, packageFact) |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | // `pass.AllPackageFacts()` returns the slice of package facts in _unspecified_ order. Here |
| 93 | // we sort the facts by package path to ensure deterministic iteration order, which is |
| 94 | // important for determinism in NilAway since our inference algorithm depends on the order of |
| 95 | // trigger / site nilability applications. |
| 96 | slices.SortFunc(facts, func(i, j analysis.PackageFact) int { |
| 97 | return cmp.Compare(i.Package.Path(), j.Package.Path()) |
| 98 | }) |
| 99 | |
| 100 | for _, f := range facts { |
| 101 | f.Fact.(*InferredMap).OrderedRange(func(site primitiveSite, val InferredVal) bool { |
| 102 | switch v := val.(type) { |
| 103 | case *DeterminedVal: |
| 104 | // Fix as an Explained site any sites that `otherMap` knows are explained |
| 105 | // This can yield an overconstrainedConflict if the current map disagrees on the |
| 106 | // value of the site. |
| 107 | e.observeSiteExplanation(site, v.Bool) |
| 108 | case *UndeterminedVal: |
| 109 | // Observe all forward implications from this site. |
| 110 | for _, p := range v.Implicates.Pairs { |
| 111 | implicantSite, assertion := p.Key, p.Value |
| 112 | e.observeImplication(site, implicantSite, assertion) |
| 113 | } |
| 114 | // Observe all backward implications from this site. |
| 115 | for _, p := range v.Implicants.Pairs { |
| 116 | implicantSite, assertion := p.Key, p.Value |
| 117 | e.observeImplication(implicantSite, site, assertion) |
| 118 | } |
| 119 | } |
| 120 | return true |
| 121 | }) |
| 122 | } |
| 123 | |
| 124 | // copy imported maps into upstreamMapping field |
| 125 | e.inferredMap.OrderedRange(func(site primitiveSite, val InferredVal) bool { |
| 126 | e.inferredMap.upstreamMapping[site] = val.copy() |
| 127 | return true |
| 128 | }) |
| 129 | } |
| 130 | |
| 131 | // ObserveAnnotations does one of two things. If the inferenceType is FullInfer, then it reads |
| 132 | // ONLY those annotations that are "set" (a separate flag for both nilability and deep nilability) |
no test coverage detected