1: <?php declare(strict_types = 1);
2:
3: namespace PHPStan\Command;
4:
5: use PHPStan\Analyser\Error;
6: use PHPStan\Analyser\InternalError;
7: use PHPStan\Collectors\CollectedData;
8: use function count;
9: use function usort;
10:
11: /**
12: * @api
13: */
14: final class AnalysisResult
15: {
16:
17: /** @var list<Error> sorted by their file name, line number and message */
18: private array $fileSpecificErrors;
19:
20: /**
21: * @param list<Error> $fileSpecificErrors
22: * @param list<string> $notFileSpecificErrors
23: * @param list<InternalError> $internalErrors
24: * @param list<string> $warnings
25: * @param list<CollectedData> $collectedData
26: * @param array<string, string> $changedProjectExtensionFilesOutsideOfAnalysedPaths
27: * @param list<string> $processedFiles
28: */
29: public function __construct(
30: array $fileSpecificErrors,
31: private array $notFileSpecificErrors,
32: private array $internalErrors,
33: private array $warnings,
34: private array $collectedData,
35: private bool $defaultLevelUsed,
36: private ?string $projectConfigFile,
37: private bool $savedResultCache,
38: private int $peakMemoryUsageBytes,
39: private bool $isResultCacheUsed,
40: private array $changedProjectExtensionFilesOutsideOfAnalysedPaths,
41: private array $processedFiles = [],
42: private bool $resultCacheExisted = true,
43: private int $workerCount = 0,
44: )
45: {
46: usort(
47: $fileSpecificErrors,
48: static fn (Error $a, Error $b): int => [
49: $a->getFile(),
50: $a->getLine(),
51: $a->getMessage(),
52: ] <=> [
53: $b->getFile(),
54: $b->getLine(),
55: $b->getMessage(),
56: ],
57: );
58:
59: $this->fileSpecificErrors = $fileSpecificErrors;
60: }
61:
62: public function hasErrors(): bool
63: {
64: return $this->getTotalErrorsCount() > 0;
65: }
66:
67: public function getTotalErrorsCount(): int
68: {
69: return count($this->fileSpecificErrors) + count($this->notFileSpecificErrors);
70: }
71:
72: /**
73: * @return list<Error> sorted by their file name, line number and message
74: */
75: public function getFileSpecificErrors(): array
76: {
77: return $this->fileSpecificErrors;
78: }
79:
80: /**
81: * @return list<string>
82: */
83: public function getNotFileSpecificErrors(): array
84: {
85: return $this->notFileSpecificErrors;
86: }
87:
88: /**
89: * @return list<InternalError>
90: */
91: public function getInternalErrorObjects(): array
92: {
93: return $this->internalErrors;
94: }
95:
96: /**
97: * @return list<string>
98: */
99: public function getWarnings(): array
100: {
101: return $this->warnings;
102: }
103:
104: public function hasWarnings(): bool
105: {
106: return count($this->warnings) > 0;
107: }
108:
109: /**
110: * @return list<CollectedData>
111: */
112: public function getCollectedData(): array
113: {
114: return $this->collectedData;
115: }
116:
117: public function isDefaultLevelUsed(): bool
118: {
119: return $this->defaultLevelUsed;
120: }
121:
122: public function getProjectConfigFile(): ?string
123: {
124: return $this->projectConfigFile;
125: }
126:
127: public function hasInternalErrors(): bool
128: {
129: return count($this->internalErrors) > 0;
130: }
131:
132: public function isResultCacheSaved(): bool
133: {
134: return $this->savedResultCache;
135: }
136:
137: public function getPeakMemoryUsageBytes(): int
138: {
139: return $this->peakMemoryUsageBytes;
140: }
141:
142: /**
143: * How many parallel workers produced this result; 0 when the analysis ran in
144: * the main process.
145: */
146: public function getWorkerCount(): int
147: {
148: return $this->workerCount;
149: }
150:
151: public function isResultCacheUsed(): bool
152: {
153: return $this->isResultCacheUsed;
154: }
155:
156: /**
157: * Whether the result cache file existed when PHPStan started.
158: * False means the cache was never created; a stale/invalid cache that
159: * triggered a full re-analysis still counts as existing.
160: */
161: public function resultCacheExisted(): bool
162: {
163: return $this->resultCacheExisted;
164: }
165:
166: /**
167: * @return array<string, string>
168: */
169: public function getChangedProjectExtensionFilesOutsideOfAnalysedPaths(): array
170: {
171: return $this->changedProjectExtensionFilesOutsideOfAnalysedPaths;
172: }
173:
174: /**
175: * @return list<string>
176: */
177: public function getProcessedFiles(): array
178: {
179: return $this->processedFiles;
180: }
181:
182: /**
183: * @api
184: * @param list<Error> $fileSpecificErrors
185: */
186: public function withFileSpecificErrors(array $fileSpecificErrors): self
187: {
188: return new self(
189: $fileSpecificErrors,
190: $this->notFileSpecificErrors,
191: $this->internalErrors,
192: $this->warnings,
193: $this->collectedData,
194: $this->defaultLevelUsed,
195: $this->projectConfigFile,
196: $this->savedResultCache,
197: $this->peakMemoryUsageBytes,
198: $this->isResultCacheUsed,
199: $this->changedProjectExtensionFilesOutsideOfAnalysedPaths,
200: $this->processedFiles,
201: $this->resultCacheExisted,
202: );
203: }
204:
205: }
206: