You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@netbeans.apache.org by ju...@apache.org on 2019/10/31 13:04:04 UTC
[netbeans] branch master updated: [NETBEANS-3002]
NullPointerExceptions during PHPStan inspection (#1592)
This is an automated email from the ASF dual-hosted git repository.
junichi11 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/netbeans.git
The following commit(s) were added to refs/heads/master by this push:
new f6fc0fc [NETBEANS-3002] NullPointerExceptions during PHPStan inspection (#1592)
f6fc0fc is described below
commit f6fc0fcff68ad47e111aa6dcc62d8e315913cf78
Author: Junichi Yamamoto <ju...@apache.org>
AuthorDate: Thu Oct 31 22:03:57 2019 +0900
[NETBEANS-3002] NullPointerExceptions during PHPStan inspection (#1592)
- The file name value can be null
e.g.
```
<file>
<error severity="error" message="Ignored error pattern #TEST# was not matched in reported errors." />
</file>
```
So, in this case, just ignore the error.
- There is a difference in file name value between the old version and the new version
e.g. Inspect the following app directory (myproject is the working directory)
- myproject/app/Test1.php
- myproject/app/Test2.php
old version: the relative path from target directory
```
<file name="Test1.php">
<error line="13" column="1" severity="error" message="Binary operation "+" between string and 2 results in an error." />
</file>
<file name="Test2.php">
<error line="9" column="1" severity="error" message="Anonymous function should return string but returns void." />
<error line="9" column="1" severity="error" message="Result of closure (void) is used." />
</file>
```
new verison: the relative path from working directory
```
<file name="app/Test1.php">
<error line="13" column="1" severity="error" message="Binary operation "+" between string and 2 results in an error." />
</file>
<file name="app/Test2.php">
<error line="9" column="1" severity="error" message="Anonymous function should return string but returns void." />
<error line="9" column="1" severity="error" message="Result of closure (void) is used." />
</file>
```
So, check also the relative path from the working directory.
---
.../modules/php/analysis/commands/PHPStan.java | 23 +++++----
.../php/analysis/parsers/PHPStanReportParser.java | 54 ++++++++++++++++------
.../phpstan/PHPStanSupport/netbeans3022/Test1.php | 3 ++
.../phpstan/PHPStanSupport/netbeans3022/Test2.php | 3 ++
.../data/phpstan/phpstan-log-netbeans-3022-win.xml | 33 +++++++++++++
.../phpstan-log-netbeans-3022-without-workdir.xml | 30 ++++++++++++
.../data/phpstan/phpstan-log-netbeans-3022.xml | 33 +++++++++++++
.../analysis/parsers/PHPStanReportParserTest.java | 36 +++++++++++++--
8 files changed, 189 insertions(+), 26 deletions(-)
diff --git a/php/php.code.analysis/src/org/netbeans/modules/php/analysis/commands/PHPStan.java b/php/php.code.analysis/src/org/netbeans/modules/php/analysis/commands/PHPStan.java
index 3ee2d30..997a561 100644
--- a/php/php.code.analysis/src/org/netbeans/modules/php/analysis/commands/PHPStan.java
+++ b/php/php.code.analysis/src/org/netbeans/modules/php/analysis/commands/PHPStan.java
@@ -102,19 +102,21 @@ public final class PHPStan {
@NbBundle.Messages({
"# {0} - counter",
- "PHPStan.analyze=PHPStan (analyze #{0})",})
+ "PHPStan.analyze=PHPStan (analyze #{0})"
+ })
@CheckForNull
public List<Result> analyze(PHPStanParams params, FileObject file) {
assert file.isValid() : "Invalid file given: " + file;
try {
- Integer result = getExecutable(Bundle.PHPStan_analyze(analyzeGroupCounter++), findWorkDir(file))
+ FileObject workDir = findWorkDir(file);
+ Integer result = getExecutable(Bundle.PHPStan_analyze(analyzeGroupCounter++), workDir == null ? null : FileUtil.toFile(workDir))
.additionalParameters(getParameters(params, file))
.runAndWait(getDescriptor(), "Running phpstan..."); // NOI18N
if (result == null) {
return null;
}
- return PHPStanReportParser.parse(XML_LOG, file);
+ return PHPStanReportParser.parse(XML_LOG, file, workDir);
} catch (CancellationException ex) {
// cancelled
return Collections.emptyList();
@@ -133,17 +135,22 @@ public final class PHPStan {
* @return project directory or {@code null}
*/
@CheckForNull
- private File findWorkDir(FileObject file) {
+ private FileObject findWorkDir(FileObject file) {
assert file != null;
Project project = FileOwnerQuery.getOwner(file);
+ FileObject workDir = null;
if (project != null) {
- File projectDir = FileUtil.toFile(project.getProjectDirectory());
+ workDir = project.getProjectDirectory();
if (LOGGER.isLoggable(Level.FINE)) {
- LOGGER.log(Level.FINE, "Project directory for {0} found in {1}", new Object[]{FileUtil.toFile(file), projectDir});
+ if (workDir != null) {
+ LOGGER.log(Level.FINE, "Project directory for {0} is found in {1}", new Object[]{FileUtil.toFile(file), workDir}); // NOI18N
+ } else {
+ // the file/directory may not be in a PHP project
+ LOGGER.log(Level.FINE, "Project directory for {0} is not found", FileUtil.toFile(file)); // NOI18N
+ }
}
- return projectDir;
}
- return null;
+ return workDir;
}
private PhpExecutable getExecutable(String title, @NullAllowed File workDir) {
diff --git a/php/php.code.analysis/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParser.java b/php/php.code.analysis/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParser.java
index 8a2937d..2ed5e47 100644
--- a/php/php.code.analysis/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParser.java
+++ b/php/php.code.analysis/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParser.java
@@ -33,6 +33,7 @@ import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NullAllowed;
import org.netbeans.modules.php.analysis.results.Result;
import org.netbeans.modules.php.api.util.FileUtils;
import org.openide.filesystems.FileObject;
@@ -56,25 +57,28 @@ public class PHPStanReportParser extends DefaultHandler {
private Result currentResult = null;
private String currentFile = null;
private final FileObject root;
+ @NullAllowed
+ private final FileObject workDir;
- private PHPStanReportParser(FileObject root) throws SAXException {
+ private PHPStanReportParser(FileObject root, @NullAllowed FileObject workDir) throws SAXException {
this.xmlReader = FileUtils.createXmlReader();
this.root = root;
+ this.workDir = workDir;
}
- private static PHPStanReportParser create(Reader reader, FileObject root) throws SAXException, IOException {
- PHPStanReportParser parser = new PHPStanReportParser(root);
+ private static PHPStanReportParser create(Reader reader, FileObject root, @NullAllowed FileObject workDir) throws SAXException, IOException {
+ PHPStanReportParser parser = new PHPStanReportParser(root, workDir);
parser.xmlReader.setContentHandler(parser);
parser.xmlReader.parse(new InputSource(reader));
return parser;
}
@CheckForNull
- public static List<Result> parse(File file, FileObject root) {
+ public static List<Result> parse(File file, FileObject root, @NullAllowed FileObject workDir) {
try {
sanitizeFile(file);
try (Reader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"))) { // NOI18N
- return create(reader, root).getResults();
+ return create(reader, root, workDir).getResults();
}
} catch (IOException | SAXException ex) {
LOGGER.log(Level.INFO, null, ex);
@@ -112,7 +116,7 @@ public class PHPStanReportParser extends DefaultHandler {
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("file".equals(qName)) { // NOI18N
processFileStart(attributes);
- } else if ("error".equals(qName)) { // NOI18N
+ } else if ("error".equals(qName) && currentFile != null) { // NOI18N
processResultStart(attributes);
}
}
@@ -130,11 +134,16 @@ public class PHPStanReportParser extends DefaultHandler {
assert currentResult == null : currentResult.getFilePath();
assert currentFile == null : currentFile;
- currentFile = getCurrentFile(attributes.getValue("name")); // NOI18N
+ // NETBEANS-3022 name value can be null
+ // e.g.
+ // <file>
+ // <error severity="error" message="Ignored error pattern #TEST# was not matched in reported errors." />
+ // </file>
+ String name = attributes.getValue("name"); // NOI18N
+ currentFile = name == null ? null : getCurrentFile(name);
}
private void processFileEnd() {
- assert currentFile != null;
currentFile = null;
}
@@ -160,8 +169,9 @@ public class PHPStanReportParser extends DefaultHandler {
}
private void processResultEnd() {
- assert currentResult != null;
- results.add(currentResult);
+ if (currentResult != null) {
+ results.add(currentResult);
+ }
currentResult = null;
}
@@ -178,20 +188,38 @@ public class PHPStanReportParser extends DefaultHandler {
@CheckForNull
private String getCurrentFile(String fileName) {
String sanitizedFileName = sanitizeFileName(fileName);
+ // if working directory is null, the file name is the absolute path
+ // e.g. <file name="/path/to/MyPHPProject/app/Test1.php">
+ File file = new File(sanitizedFileName);
+ if (file.isAbsolute()) {
+ return file.getAbsolutePath();
+ }
+
+ String currentFilePath = sanitizedFileName;
FileObject rootDirectory = root;
if (!root.isFolder()) {
rootDirectory = root.getParent();
}
if (rootDirectory.isFolder()) {
+ // windows: <file name="app\index.php">
+ sanitizedFileName = sanitizedFileName.replace('\\', '/');
FileObject current = rootDirectory.getFileObject(sanitizedFileName);
if (current == null) {
+ // NETBANS-3022 try checking relative file path from working directory
+ if (workDir != null) {
+ rootDirectory = workDir;
+ current = rootDirectory.getFileObject(sanitizedFileName);
+ }
+ }
+ if (current == null) {
LOGGER.log(Level.WARNING, "Cannot get the current file: file name {0}, root directory {1}", // NOI18N
new Object[]{fileName, FileUtil.toFile(rootDirectory).getAbsolutePath()});
- return null;
+ currentFilePath = null;
+ } else {
+ currentFilePath = FileUtil.toFile(current).getAbsolutePath();
}
- return FileUtil.toFile(current).getAbsolutePath();
}
- return sanitizedFileName;
+ return currentFilePath;
}
private String sanitizeFileName(String fileName) {
diff --git a/php/php.code.analysis/test/unit/data/phpstan/PHPStanSupport/netbeans3022/Test1.php b/php/php.code.analysis/test/unit/data/phpstan/PHPStanSupport/netbeans3022/Test1.php
new file mode 100644
index 0000000..90c534d
--- /dev/null
+++ b/php/php.code.analysis/test/unit/data/phpstan/PHPStanSupport/netbeans3022/Test1.php
@@ -0,0 +1,3 @@
+<?php
+/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements; and to You under the Apache License, Version 2.0. */
+// dummy file
diff --git a/php/php.code.analysis/test/unit/data/phpstan/PHPStanSupport/netbeans3022/Test2.php b/php/php.code.analysis/test/unit/data/phpstan/PHPStanSupport/netbeans3022/Test2.php
new file mode 100644
index 0000000..90c534d
--- /dev/null
+++ b/php/php.code.analysis/test/unit/data/phpstan/PHPStanSupport/netbeans3022/Test2.php
@@ -0,0 +1,3 @@
+<?php
+/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements; and to You under the Apache License, Version 2.0. */
+// dummy file
diff --git a/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022-win.xml b/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022-win.xml
new file mode 100644
index 0000000..04185ce
--- /dev/null
+++ b/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022-win.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<checkstyle>
+<file name="netbeans3022\Test1.php">
+ <error line="13" column="1" severity="error" message="Binary operation "+" between string and 2 results in an error." />
+</file>
+<file name="netbeans3022\Test2.php">
+ <error line="9" column="1" severity="error" message="Anonymous function should return string but returns void." />
+ <error line="9" column="1" severity="error" message="Result of closure (void) is used." />
+</file>
+<file>
+ <error severity="error" message="Ignored error pattern #TEST# was not matched in reported errors." />
+</file>
+</checkstyle>
diff --git a/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022-without-workdir.xml b/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022-without-workdir.xml
new file mode 100644
index 0000000..56460df
--- /dev/null
+++ b/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022-without-workdir.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<checkstyle>
+<file name="/home/junichi11/NetBeansProjects/PHPStan/app/Test1.php">
+ <error line="13" column="1" severity="error" message="Binary operation "+" between string and 2 results in an error." />
+</file>
+<file name="/home/junichi11/NetBeansProjects/PHPStan/app/Test2.php">
+ <error line="9" column="1" severity="error" message="Anonymous function should return string but returns void." />
+ <error line="9" column="1" severity="error" message="Result of closure (void) is used." />
+</file>
+</checkstyle>
diff --git a/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022.xml b/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022.xml
new file mode 100644
index 0000000..8c04456
--- /dev/null
+++ b/php/php.code.analysis/test/unit/data/phpstan/phpstan-log-netbeans-3022.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<checkstyle>
+<file name="netbeans3022/Test1.php">
+ <error line="13" column="1" severity="error" message="Binary operation "+" between string and 2 results in an error." />
+</file>
+<file name="netbeans3022/Test2.php">
+ <error line="9" column="1" severity="error" message="Anonymous function should return string but returns void." />
+ <error line="9" column="1" severity="error" message="Result of closure (void) is used." />
+</file>
+<file>
+ <error severity="error" message="Ignored error pattern #TEST# was not matched in reported errors." />
+</file>
+</checkstyle>
diff --git a/php/php.code.analysis/test/unit/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParserTest.java b/php/php.code.analysis/test/unit/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParserTest.java
index cdb74f2..cd41d38 100644
--- a/php/php.code.analysis/test/unit/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParserTest.java
+++ b/php/php.code.analysis/test/unit/src/org/netbeans/modules/php/analysis/parsers/PHPStanReportParserTest.java
@@ -35,8 +35,9 @@ public class PHPStanReportParserTest extends NbTestCase {
}
public void testParse() throws Exception {
- FileObject root = getRoot("phpstan/PHPStanSupport");
- List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log.xml"), root);
+ FileObject root = getDataDir("phpstan/PHPStanSupport");
+ FileObject workDir = root;
+ List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log.xml"), root, workDir);
assertNotNull(results);
assertEquals(4, results.size());
@@ -61,12 +62,37 @@ public class PHPStanReportParserTest extends NbTestCase {
}
public void testParseWithOtherOutput() throws Exception {
- FileObject root = getRoot("phpstan/PHPStanSupport");
- List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log-with-other-output.xml"), root);
+ FileObject root = getDataDir("phpstan/PHPStanSupport");
+ FileObject workDir = root;
+ List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log-with-other-output.xml"), root, workDir);
assertNotNull(results);
assertEquals(2, results.size());
}
+ public void testParseNetBeans3022() throws Exception {
+ FileObject root = getDataDir("phpstan/PHPStanSupport/netbeans3022");
+ FileObject workDir = getDataDir("phpstan/PHPStanSupport");
+ List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log-netbeans-3022.xml"), root, workDir);
+ assertNotNull(results);
+ assertEquals(3, results.size());
+ }
+
+ public void testParseNetBeans3022Win() throws Exception {
+ FileObject root = getDataDir("phpstan/PHPStanSupport/netbeans3022");
+ FileObject workDir = getDataDir("phpstan/PHPStanSupport");
+ List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log-netbeans-3022-win.xml"), root, workDir);
+ assertNotNull(results);
+ assertEquals(3, results.size());
+ }
+
+ public void testParseNetBeans3022WithoutWorkDir() throws Exception {
+ FileObject root = getDataDir("phpstan/PHPStanSupport/netbeans3022");
+ FileObject workDir = null;
+ List<Result> results = PHPStanReportParser.parse(getLogFile("phpstan-log-netbeans-3022-without-workdir.xml"), root, workDir);
+ assertNotNull(results);
+ assertEquals(3, results.size());
+ }
+
private File getLogFile(String name) throws Exception {
assertNotNull(name);
File phpstan = new File(getDataDir(), "phpstan");
@@ -75,7 +101,7 @@ public class PHPStanReportParserTest extends NbTestCase {
return xmlLog;
}
- private FileObject getRoot(String name) {
+ private FileObject getDataDir(String name) {
assertNotNull(name);
FileObject dataDir = FileUtil.toFileObject(getDataDir());
return dataDir.getFileObject(name);
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@netbeans.apache.org
For additional commands, e-mail: commits-help@netbeans.apache.org
For further information about the NetBeans mailing lists, visit:
https://cwiki.apache.org/confluence/display/NETBEANS/Mailing+lists