Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 93 additions & 0 deletions build/fix-inheritdoc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/

include __DIR__ . '/../lib/composer/autoload.php';
include __DIR__ . '/../build/integration/vendor/autoload.php';
include __DIR__ . '/../3rdparty/autoload.php';

use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\NodeTraverser;
use PhpParser\NodeVisitor\CloningVisitor;
use PhpParser\NodeVisitor\NameResolver;
use PhpParser\ParserFactory;
use PhpParser\PrettyPrinter;

$parser = (new ParserFactory())->createForHostVersion();

$nodeTraverser = new NodeTraverser();
$nodeTraverser->addVisitor(new CloningVisitor());
$nodeTraverser->addVisitor(new NameResolver());

$prettyPrinter = new PrettyPrinter\Standard();

$iterators = [
new RecursiveIteratorIterator(new RecursiveDirectoryIterator('lib/private')),
new RecursiveIteratorIterator(new RecursiveDirectoryIterator('core')),
];
foreach ($iterators as $iterator) {
/** @var SplFileInfo $info */
foreach ($iterator as $info) {
if ($info->getType() !== 'file' || $info->getExtension() !== 'php') {
continue;
}

$code = file_get_contents($info->getRealPath());
$oldStmts = $parser->parse($code);
$oldTokens = $parser->getTokens();
$newStmts = $nodeTraverser->traverse($oldStmts);

$changed = false;
foreach ($newStmts as $stmt) {
if (!$stmt instanceof Namespace_) {
continue;
}

foreach ($stmt->stmts as $childClass) {
if (!$childClass instanceof Class_) {
continue;
}

$childClassName = $childClass->namespacedName->toString();
if (!str_starts_with($childClassName, 'OC\\')) {
continue;
}

/** @var FullyQualified $impl */
foreach ($childClass->implements as $impl) {
$parentClassName = $impl->toString();
if ($parentClassName === 'OCP\\Capabilities\\ICapability' || $parentClassName === 'OCP\\Capabilities\\IPublicCapability' || !str_starts_with($parentClassName, 'OCP\\')) {
continue;
}

$parentClass = new ReflectionClass($parentClassName);
$parentMethods = $parentClass->getMethods();

foreach ($childClass->getMethods() as $childMethod) {
foreach ($parentMethods as $parentMethod) {
if (strtolower($childMethod->name->name) !== strtolower($parentMethod->name)) {
continue;
}

$childMethod->setAttribute('comments', []);
$changed = true;
break;
}
}
}
}
}

if ($changed) {
file_put_contents($info->getRealPath(), $prettyPrinter->printFormatPreserving($newStmts, $oldStmts, $oldTokens));
}
}
}
64 changes: 64 additions & 0 deletions build/psalm/OcInheritDoc.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-only
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* SPDX-License-Identifier: AGPL-3.0-only
* SPDX-License-Identifier: AGPL-3.0-or-later

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script will be removed from the PR anyway. When it is fixed once it is enforced by psalm so the script will never be needed again as everyone has to set the correct doc blocks in their PRs already.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry 🙈

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No worries, I never said what is going to happen with this PR.
I plan to fix the issues that were found in separate PRs and once that is done we can merge the PR.

*/

use PhpParser\Node\Name;
use PhpParser\Node\Stmt\Class_;
use Psalm\CodeLocation;
use Psalm\Issue\InvalidDocblock;
use Psalm\IssueBuffer;
use Psalm\Plugin\EventHandler\Event\AfterClassLikeVisitEvent;

include __DIR__ . '/../../3rdparty/autoload.php';

class OcInheritDoc implements Psalm\Plugin\EventHandler\AfterClassLikeVisitInterface {
public static function afterClassLikeVisit(AfterClassLikeVisitEvent $event): void {
$childClass = $event->getStmt();
$statementsSource = $event->getStatementsSource();

if (!$childClass instanceof Class_) {
return;
}

$childClassName = $childClass->getAttribute('namespacedName')?->toString() ?? '';
if (!str_starts_with($childClassName, 'OC\\')) {
return;
}

/** @var Name $impl */
foreach ($childClass->implements as $impl) {
$parentClassName = $impl->getAttribute('resolvedName') ?? '';
if ($parentClassName === 'OCP\\Capabilities\\ICapability' || $parentClassName === 'OCP\\Capabilities\\IPublicCapability' || !str_starts_with($parentClassName, 'OCP\\')) {
continue;
}

$parentClass = new ReflectionClass($parentClassName);
$parentMethods = $parentClass->getMethods();

foreach ($childClass->getMethods() as $childMethod) {
foreach ($parentMethods as $parentMethod) {
if (strtolower($childMethod->name->name) !== strtolower($parentMethod->name)) {
continue;
}

$doc = $childMethod->getDocComment();
if ($doc !== null) {
IssueBuffer::maybeAdd(
new InvalidDocblock(
'Docblock for OCP implementation must be empty to inherit the interface.',
new CodeLocation($statementsSource, $childMethod)
)
);
}

break;
}
}
}
}
}
12 changes: 0 additions & 12 deletions core/Notification/CoreNotifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,10 @@ public function __construct(
) {
}

/**
* Identifier of the notifier, only use [a-z0-9_]
*
* @return string
* @since 17.0.0
*/
public function getID(): string {
return 'core';
}

/**
* Human readable name describing the notifier
*
* @return string
* @since 17.0.0
*/
public function getName(): string {
return $this->factory->get('core')->t('Nextcloud Server');
}
Expand Down
1 change: 0 additions & 1 deletion lib/private/Accounts/Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ public function getFilteredProperties(?string $scope = null, ?string $verified =
return $result;
}

/** @return array<string, IAccountProperty|array<int, IAccountProperty>> */
public function jsonSerialize(): array {
$properties = $this->properties;
foreach ($properties as $propertyName => $propertyObject) {
Expand Down
35 changes: 0 additions & 35 deletions lib/private/Accounts/AccountProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,11 @@ public function jsonSerialize(): array {
];
}

/**
* Set the value of a property
*
* @since 15.0.0
*/
public function setValue(string $value): IAccountProperty {
$this->value = $value;
return $this;
}

/**
* Set the scope of a property
*
* @since 15.0.0
*/
public function setScope(string $scope): IAccountProperty {
$newScope = $this->mapScopeToV2($scope);
if (!in_array($newScope, [
Expand All @@ -68,39 +58,19 @@ public function setScope(string $scope): IAccountProperty {
return $this;
}

/**
* Set the verification status of a property
*
* @since 15.0.0
*/
public function setVerified(string $verified): IAccountProperty {
$this->verified = $verified;
return $this;
}

/**
* Get the name of a property
*
* @since 15.0.0
*/
public function getName(): string {
return $this->name;
}

/**
* Get the value of a property
*
* @since 15.0.0
*/
public function getValue(): string {
return $this->value;
}

/**
* Get the scope of a property
*
* @since 15.0.0
*/
public function getScope(): string {
return $this->scope;
}
Expand All @@ -118,11 +88,6 @@ public static function mapScopeToV2(string $scope): string {
};
}

/**
* Get the verification status of a property
*
* @since 15.0.0
*/
public function getVerified(): string {
return $this->verified;
}
Expand Down
Loading