Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix incorrect unused coloring #5551 #5670

Merged
merged 1 commit into from
Mar 18, 2023
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ public ASTNodeColoring(ASTNode identifier, Set<ColoringAttributes> coloring) {
// for unsed private method: name, identifier
private final Map<UnusedIdentifier, ASTNodeColoring> privateUnusedMethods;
// this is holder of blocks, which has to be scanned for usages in the class.
private List<Block> needToScan = new ArrayList<>();
private final Map<TypeInfo, List<Block>> needToScan = new HashMap<>();

private final Snapshot snapshot;

Expand Down Expand Up @@ -409,18 +409,16 @@ public void visit(ClassDeclaration cldec) {
scan(cldec.getInterfaes());
Identifier name = cldec.getName();
addColoringForNode(name, createTypeNameColoring(name));
needToScan = new ArrayList<>();
needToScan.put(typeInfo, new ArrayList<>());
if (cldec.getBody() != null) {
cldec.getBody().accept(this);

// find all usages in the method bodies
while (!needToScan.isEmpty()) {
Block block = needToScan.remove(0);
block.accept(this);
}
scanMethodBodies();
addColoringForUnusedPrivateConstants();
addColoringForUnusedPrivateFields();
}
needToScan.remove(typeInfo);
removeFromPath();
}

Expand Down Expand Up @@ -515,8 +513,8 @@ public void visit(MethodDeclaration md) {
// don't scan the body now. It should be scanned after all declarations
// are known
Block body = md.getFunction().getBody();
if (body != null) {
needToScan.add(body);
if (body != null && needToScan.get(typeInfo) != null) {
needToScan.get(typeInfo).add(body);
}
}
}
Expand Down Expand Up @@ -595,23 +593,24 @@ public void visit(ClassInstanceCreation node) {
// to avoid recognizing $this as an instance of an anonymous class
scan(node.ctorParams());
addToPath(node);
// GH-5551 keep original type info to scan parent blocks
TypeInfo originalTypeInfo = typeInfo;
typeInfo = new ClassInstanceCreationTypeInfo(node);
scan(node.getAttributes());
scan(node.getSuperClass());
scan(node.getInterfaces());
needToScan = new ArrayList<>();
needToScan.put(typeInfo, new ArrayList<>());
Block body = node.getBody();
if (body != null) {
body.accept(this);

// find all usages in the method bodies
while (!needToScan.isEmpty()) {
Block block = needToScan.remove(0);
block.accept(this);
}
scanMethodBodies();
addColoringForUnusedPrivateConstants();
addColoringForUnusedPrivateFields();
}
needToScan.remove(typeInfo);
typeInfo = originalTypeInfo;
removeFromPath();
} else {
super.visit(node);
Expand Down Expand Up @@ -639,14 +638,13 @@ public void visit(TraitDeclaration node) {
typeInfo = new TypeDeclarationTypeInfo(node);
Identifier name = node.getName();
addColoringForNode(name, createTypeNameColoring(name));
needToScan = new ArrayList<>();
needToScan.put(typeInfo, new ArrayList<>());
if (node.getBody() != null) {
node.getBody().accept(this);
for (Block block : needToScan) {
block.accept(this);
}
scanMethodBodies();
addColoringForUnusedPrivateFields();
}
needToScan.remove(typeInfo);
removeFromPath();
}

Expand All @@ -661,13 +659,12 @@ public void visit(EnumDeclaration node) {
typeInfo = new TypeDeclarationTypeInfo(node);
Identifier name = node.getName();
addColoringForNode(name, createTypeNameColoring(name));
needToScan = new ArrayList<>();
needToScan.put(typeInfo, new ArrayList<>());
if (node.getBody() != null) {
node.getBody().accept(this);
for (Block block : needToScan) {
block.accept(this);
}
scanMethodBodies();
}
needToScan.remove(typeInfo);
removeFromPath();
}

Expand Down Expand Up @@ -991,6 +988,19 @@ public void visit(NamedArgument node) {
super.visit(node);
}

/**
* Find all usages in the method bodies.
*/
private void scanMethodBodies() {
if (needToScan.get(typeInfo) == null) {
return;
}
for (Block block : needToScan.get(typeInfo)) {
block.accept(this);
}
needToScan.get(typeInfo).clear();
}

private class FieldAccessVisitor extends DefaultVisitor {
private final Set<ColoringAttributes> coloring;

Expand Down
51 changes: 51 additions & 0 deletions php/php.editor/test/unit/data/testfiles/semantic/gh5551_01.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
class TestClass {
public function testMethod(string $test): string {
return $test;
}
}

interface TestInterface {
public function testMethod(string $test): string;
}

class GH5551 {

private function usedPrivateMethod1(): TestClass {
return new TestClass();
}

private function usedPrivateMethod2(): TestInterface {
return new class implements TestInterface {
public function testMethod(string $test): string {
return $test;
}
};
}

private function unusedPrivateMethod(): void {
}

public function test() {
echo $this->usedPrivateMethod1()->testMethod("test1"), PHP_EOL;
echo $this->usedPrivateMethod2()->testMethod("test2"), PHP_EOL;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
class |>CLASS:TestClass<| {
public function |>METHOD:testMethod<|(string $test): string {
return $test;
}
}

interface |>CLASS:TestInterface<| {
public function |>METHOD:testMethod<|(string $test): string;
}

class |>CLASS:GH5551<| {

private function |>METHOD:usedPrivateMethod1<|(): TestClass {
return new TestClass();
}

private function |>METHOD:usedPrivateMethod2<|(): TestInterface {
return new class implements TestInterface {
public function |>METHOD:testMethod<|(string $test): string {
return $test;
}
};
}

private function |>METHOD,UNUSED:unusedPrivateMethod<|(): void {
}

public function |>METHOD:test<|() {
echo $this->|>CUSTOM1:usedPrivateMethod1<|()->|>CUSTOM1:testMethod<|("test1"), PHP_EOL;
echo $this->|>CUSTOM1:usedPrivateMethod2<|()->|>CUSTOM1:testMethod<|("test2"), PHP_EOL;
}
}
59 changes: 59 additions & 0 deletions php/php.editor/test/unit/data/testfiles/semantic/gh5551_02.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
class TestClass {
public function testMethod(string $test): string {
return $test;
}
}

interface TestInterface {
public function testMethod(string $test): string;
}

class GH5551 {

private function usedPrivateMethod1(): TestClass {
return new TestClass();
}

private function usedPrivateMethod2(): TestInterface {
return new class implements TestInterface {

private function unusedPrivateMethod(): void {
}

private function usedPrivateMethod(): void {
}

public function testMethod(string $test): string {
$this->usedPrivateMethod();
return $test;
}
};
}

private function unusedPrivateMethod(): void {
}

public function test() {
echo $this->usedPrivateMethod1()->testMethod("test1"), PHP_EOL;
echo $this->usedPrivateMethod2()->testMethod("test2"), PHP_EOL;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
class |>CLASS:TestClass<| {
public function |>METHOD:testMethod<|(string $test): string {
return $test;
}
}

interface |>CLASS:TestInterface<| {
public function |>METHOD:testMethod<|(string $test): string;
}

class |>CLASS:GH5551<| {

private function |>METHOD:usedPrivateMethod1<|(): TestClass {
return new TestClass();
}

private function |>METHOD:usedPrivateMethod2<|(): TestInterface {
return new class implements TestInterface {

private function |>METHOD,UNUSED:unusedPrivateMethod<|(): void {
}

private function |>METHOD:usedPrivateMethod<|(): void {
}

public function |>METHOD:testMethod<|(string $test): string {
$this->|>CUSTOM1:usedPrivateMethod<|();
return $test;
}
};
}

private function |>METHOD,UNUSED:unusedPrivateMethod<|(): void {
}

public function |>METHOD:test<|() {
echo $this->|>CUSTOM1:usedPrivateMethod1<|()->|>CUSTOM1:testMethod<|("test1"), PHP_EOL;
echo $this->|>CUSTOM1:usedPrivateMethod2<|()->|>CUSTOM1:testMethod<|("test2"), PHP_EOL;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -217,4 +217,12 @@ public void testEnumerations() throws Exception {
public void testConstantsInTraits() throws Exception {
checkSemantic("testfiles/semantic/constantsInTraits.php");
}

public void testGH5551_01() throws Exception {
checkSemantic("testfiles/semantic/gh5551_01.php");
}

public void testGH5551_02() throws Exception {
checkSemantic("testfiles/semantic/gh5551_02.php");
}
}