Skip to content

Commit 8cff930

Browse files
committed
PHP 8.4 Support: Property hooks (Part 4)
- apache#8035 - https://wiki.php.net/rfc#php_84 - https://wiki.php.net/rfc/property-hooks - Fix the folding feature - Add unit tests
1 parent 0935fb4 commit 8cff930

File tree

8 files changed

+614
-20
lines changed

8 files changed

+614
-20
lines changed

php/php.editor/src/org/netbeans/modules/php/editor/csl/FoldingScanner.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@
3737
import org.netbeans.modules.parsing.api.Source;
3838
import org.netbeans.modules.php.editor.lexer.LexUtilities;
3939
import org.netbeans.modules.php.editor.lexer.PHPTokenId;
40+
import org.netbeans.modules.php.editor.model.FieldElement;
4041
import org.netbeans.modules.php.editor.model.FileScope;
4142
import org.netbeans.modules.php.editor.model.FunctionScope;
4243
import org.netbeans.modules.php.editor.model.GroupUseScope;
4344
import org.netbeans.modules.php.editor.model.MethodScope;
4445
import org.netbeans.modules.php.editor.model.Model;
4546
import org.netbeans.modules.php.editor.model.ModelElement;
47+
import org.netbeans.modules.php.editor.model.PropertyHookScope;
4648
import org.netbeans.modules.php.editor.model.Scope;
4749
import org.netbeans.modules.php.editor.model.TypeScope;
4850
import org.netbeans.modules.php.editor.model.UseScope;
@@ -108,6 +110,16 @@ public final class FoldingScanner {
108110
Bundle.FT_Functions(),
109111
FoldTemplate.DEFAULT_BLOCK);
110112

113+
@NbBundle.Messages("FT_HookedFields=Fields(Properties)")
114+
public static final FoldType TYPE_HOOKED_FIELD = FoldType.MEMBER.derive("field", // NOI18N
115+
Bundle.FT_HookedFields(),
116+
FoldTemplate.DEFAULT_BLOCK);
117+
118+
@NbBundle.Messages("FT_PropertyHooks=Property hooks")
119+
public static final FoldType TYPE_PROPERTY_HOOK = FoldType.MEMBER.derive("property hook", // NOI18N
120+
Bundle.FT_PropertyHooks(),
121+
FoldTemplate.DEFAULT_BLOCK);
122+
111123
@NbBundle.Messages("FT_Arrays=Arrays")
112124
public static final FoldType TYPE_ARRAY = FoldType.NESTED.derive(
113125
"array",
@@ -273,21 +285,25 @@ private void processPHPTags(Map<String, List<OffsetRange>> folds, Document docum
273285

274286
private void processScopes(Map<String, List<OffsetRange>> folds, List<Scope> scopes) {
275287
processUseScopes(folds, scopes);
276-
processTypeAndFunctionScopes(folds, scopes);
288+
processTypeAndMemberScopes(folds, scopes);
277289
}
278290

279-
private void processTypeAndFunctionScopes(Map<String, List<OffsetRange>> folds, List<Scope> scopes) {
291+
private void processTypeAndMemberScopes(Map<String, List<OffsetRange>> folds, List<Scope> scopes) {
280292
for (Scope scope : scopes) {
281293
OffsetRange offsetRange = scope.getBlockRange();
282294
if (offsetRange == null || offsetRange.getLength() <= 1) {
283295
continue;
284296
}
285297
if (scope instanceof TypeScope) {
286298
getRanges(folds, TYPE_CLASS).add(offsetRange);
287-
} else {
288-
if (scope instanceof FunctionScope || scope instanceof MethodScope) {
289-
getRanges(folds, TYPE_FUNCTION).add(offsetRange);
299+
} else if (scope instanceof FunctionScope || scope instanceof MethodScope) {
300+
getRanges(folds, TYPE_FUNCTION).add(offsetRange);
301+
} else if (scope instanceof FieldElement.HookedFieldElement field) {
302+
if (field.isHooked()) {
303+
getRanges(folds, TYPE_HOOKED_FIELD).add(offsetRange);
290304
}
305+
} else if (scope instanceof PropertyHookScope) {
306+
getRanges(folds, TYPE_PROPERTY_HOOK).add(offsetRange);
291307
}
292308
}
293309
}

php/php.editor/src/org/netbeans/modules/php/editor/csl/PHPFoldingProvider.java

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
*/
1919
package org.netbeans.modules.php.editor.csl;
2020

21-
import java.util.ArrayList;
2221
import java.util.Collection;
22+
import java.util.List;
2323
import org.netbeans.api.editor.fold.FoldType;
2424
import org.netbeans.api.editor.mimelookup.MimeRegistration;
2525
import org.netbeans.modules.php.api.util.FileUtils;
@@ -32,22 +32,22 @@
3232
@MimeRegistration(mimeType = FileUtils.PHP_MIME_TYPE, service = FoldTypeProvider.class, position = 1000)
3333
public class PHPFoldingProvider implements FoldTypeProvider {
3434

35-
private static final Collection<FoldType> TYPES = new ArrayList<>(9);
36-
37-
static {
38-
TYPES.add(FoldingScanner.TYPE_CLASS);
39-
TYPES.add(FoldingScanner.TYPE_FUNCTION);
40-
TYPES.add(FoldingScanner.TYPE_CODE_BLOCKS);
41-
TYPES.add(FoldingScanner.TYPE_COMMENT);
42-
TYPES.add(FoldingScanner.TYPE_PHPDOC);
43-
TYPES.add(FoldingScanner.TYPE_ARRAY);
44-
TYPES.add(FoldingScanner.TYPE_USE);
45-
TYPES.add(FoldingScanner.TYPE_PHPTAG);
46-
TYPES.add(FoldingScanner.TYPE_ATTRIBUTES);
47-
}
35+
private static final Collection<FoldType> TYPES = List.of(
36+
FoldingScanner.TYPE_CLASS,
37+
FoldingScanner.TYPE_FUNCTION,
38+
FoldingScanner.TYPE_HOOKED_FIELD,
39+
FoldingScanner.TYPE_PROPERTY_HOOK,
40+
FoldingScanner.TYPE_CODE_BLOCKS,
41+
FoldingScanner.TYPE_COMMENT,
42+
FoldingScanner.TYPE_PHPDOC,
43+
FoldingScanner.TYPE_ARRAY,
44+
FoldingScanner.TYPE_USE,
45+
FoldingScanner.TYPE_PHPTAG,
46+
FoldingScanner.TYPE_ATTRIBUTES
47+
);
4848

4949
@Override
50-
public Collection getValues(Class type) {
50+
public Collection<FoldType> getValues(Class type) {
5151
return type == FoldType.class ? TYPES : null;
5252
}
5353

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
<?php
2+
+ /*
3+
| * Licensed to the Apache Software Foundation (ASF) under one
4+
| * or more contributor license agreements. See the NOTICE file
5+
| * distributed with this work for additional information
6+
| * regarding copyright ownership. The ASF licenses this file
7+
| * to you under the Apache License, Version 2.0 (the
8+
| * "License"); you may not use this file except in compliance
9+
| * with the License. You may obtain a copy of the License at
10+
| *
11+
| * http://www.apache.org/licenses/LICENSE-2.0
12+
| *
13+
| * Unless required by applicable law or agreed to in writing,
14+
| * software distributed under the License is distributed on an
15+
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
| * KIND, either express or implied. See the License for the
17+
| * specific language governing permissions and limitations
18+
| * under the License.
19+
- */
20+
+ class PropertyHooksClass {
21+
| public const string CONSTANT = "property hook";
22+
| // valid properties
23+
+ public $valid01 {
24+
+ get {
25+
| return $this->prop1;
26+
- }
27+
+ set {
28+
| $this->valid01 = $value;
29+
- }
30+
- }
31+
+ public int $valid02 = 1 {
32+
+ get {
33+
| echo __METHOD__, "\n";
34+
| return $this->valid02;
35+
- }
36+
+ set($value){
37+
| $this->valid02 = $value;
38+
- }
39+
- }
40+
+ public $valid03 = "string" {
41+
+ get {
42+
| return $this->valid03;
43+
- }
44+
+ set {}
45+
- }
46+
+ public string $valid04 = self::CONSTANT {
47+
+ get => $this->valid04;
48+
+ set {}
49+
- }
50+
+ public array $valid05 = [] {
51+
+ get => $this->valid05;
52+
+ set => $this->valid05 = $value;
53+
- }
54+
+ public private(set) string $valid06 = self::CONSTANT {
55+
+ get {
56+
| return $this->valid06 . "test";
57+
- }
58+
+ set {}
59+
- }
60+
+ public $valid07 { // virtual
61+
+ get => $this->test();
62+
+ set => $this->test() . $value;
63+
- }
64+
+ public string $valid08 {
65+
+ set(string|array $param) {
66+
| $this->valid08 = is_array($param) ? join(', ', $param) : $param;
67+
- }
68+
- }
69+
+ public $valid09 {
70+
+ #[Attr1] get {}
71+
+ #[Attr2] set {}
72+
- }
73+
+ public $valid10 = 100 {
74+
+ get {
75+
| yield 1;
76+
| yield $this->valid10;
77+
| yield 3;
78+
- }
79+
- }
80+
+ public $valid11 { // virtual
81+
+ get {
82+
| yield 1;
83+
| yield 2;
84+
| yield 3;
85+
- }
86+
- }
87+
+ public $valid12 {
88+
+ set(#[SensitiveParameter] $value) {
89+
| throw new Exception('test');
90+
- }
91+
- }
92+
+ public $valid13 {
93+
+ final get { return 100; }
94+
- }
95+
+ final public $valid14 {
96+
+ final get => $this->valid14;
97+
- }
98+
+ public $valid15 {
99+
+ &get => $this->valid15;
100+
- }
101+
+ public $closure {
102+
+ get {
103+
| return function () {
104+
| return $this->closure;
105+
| };
106+
- }
107+
- }
108+
+ public $arrowFunction {
109+
+ get {
110+
| return fn() => $this->arrowFunction;
111+
- }
112+
- }
113+
+ private $propertyConst {
114+
+ get => __PROPERTY__;
115+
- }
116+
+ var $var { get => 100; }
117+
|
118+
| // invalid properties
119+
+ public $invalidEmptyHook {} // error but parser allows
120+
+ private $invalidPrivateFinal { final get; } // error but parser allows
121+
+ private $invalidPublic01 {
122+
| public get; // error but parser allows
123+
- }
124+
+ public $invalidStatic01 {
125+
+ static get {} // error but parser allows
126+
- }
127+
+ public static $invalidStatic02 { // error but parser allows
128+
| get;
129+
| set;
130+
- }
131+
+ public $invalidGetParam {
132+
+ get() { // error but parser allows
133+
| var_dump($value);
134+
- }
135+
- }
136+
+ public readonly int $invalidReadonly { get{} set{} } // error but parser allows
137+
+ public $invalidSetRef {
138+
+ set(&$value) {} // error but parser allows
139+
- }
140+
+ public $invalidVariadic {
141+
+ set(...$value) {} // error but parser allows
142+
- }
143+
+ public $invalidUnknownHook {
144+
+ unknown {} // error
145+
- }
146+
- }
147+
148+
+ class Child extends PropertyHooksClass {
149+
+ public $prop = 100 {
150+
+ get => parent::$prop::get();
151+
+ set {
152+
| parent::$prop::set($value);
153+
- }
154+
- }
155+
- }
156+
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
+ /*
3+
| * Licensed to the Apache Software Foundation (ASF) under one
4+
| * or more contributor license agreements. See the NOTICE file
5+
| * distributed with this work for additional information
6+
| * regarding copyright ownership. The ASF licenses this file
7+
| * to you under the Apache License, Version 2.0 (the
8+
| * "License"); you may not use this file except in compliance
9+
| * with the License. You may obtain a copy of the License at
10+
| *
11+
| * http://www.apache.org/licenses/LICENSE-2.0
12+
| *
13+
| * Unless required by applicable law or agreed to in writing,
14+
| * software distributed under the License is distributed on an
15+
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16+
| * KIND, either express or implied. See the License for the
17+
| * specific language governing permissions and limitations
18+
| * under the License.
19+
- */
20+
+ abstract class AbstractClass {
21+
| // valid properties
22+
+ public abstract $valid01 { // OK
23+
| get;
24+
| set;
25+
- }
26+
+ public abstract $valid02 { // OK
27+
| get;
28+
+ set {
29+
| echo __METHOD__ . PHP_EOL;
30+
- }
31+
- }
32+
+ public abstract $valid03 { // OK
33+
+ get {
34+
| echo __METHOD__ . PHP_EOL;
35+
- }
36+
| set;
37+
- }
38+
+ protected abstract int $valid04 { get; set; } // OK
39+
|
40+
| // invalid properties
41+
+ public abstract $invalid01 { // error
42+
+ get{}
43+
+ set{}
44+
- }
45+
+ private abstract int $invalid02 { get; set; } // error
46+
| abstract public $invalid03; // error
47+
- }
48+

0 commit comments

Comments
 (0)