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/07/24 10:35:06 UTC

[netbeans] branch php7.4 updated: [NETBEANS-2873] Suggest using combined assignment operators

This is an automated email from the ASF dual-hosted git repository.

junichi11 pushed a commit to branch php7.4
in repository https://gitbox.apache.org/repos/asf/netbeans.git


The following commit(s) were added to refs/heads/php7.4 by this push:
     new 56e1290  [NETBEANS-2873] Suggest using combined assignment operators
     new d644beb  Merge pull request #1393 from junichi11/netbeans-2873-combined-assignment-operators-hint
56e1290 is described below

commit 56e12904bdfc2af9b23a2dc9c45aac5eba31f2b2
Author: Junichi Yamamoto <ju...@apache.org>
AuthorDate: Sun Jul 21 08:37:26 2019 +0900

    [NETBEANS-2873] Suggest using combined assignment operators
    
    e.g.
    ```
    // ??
    $string = $string ?? "value"; // before
    $string ??= "value"; // after
    
    // +
    $x = $x + 100; // before
    $x += 100; // after
    ```
---
 .../editor/parser/astnodes/InfixExpression.java    |   8 +-
 .../modules/php/editor/resources/layer.xml         |   1 +
 .../CombinedAssignmentOperatorSuggestion.java      | 296 +++++++++++++++++++++
 .../testAnd.php                                    |  22 ++
 .../testAnd.php.testAndFix_01.fixed                |  22 ++
 .../testAnd.php.testAnd_01.hints                   |   4 +
 .../testConcat.php                                 |  22 ++
 .../testConcat.php.testConcatFix_01.fixed          |  22 ++
 .../testConcat.php.testConcat_01.hints             |   4 +
 .../testDiv.php                                    |  22 ++
 .../testDiv.php.testDivFix_01.fixed                |  22 ++
 .../testDiv.php.testDiv_01.hints                   |   4 +
 .../testMinus.php                                  |  22 ++
 .../testMinus.php.testMinusFix_01.fixed            |  22 ++
 .../testMinus.php.testMinus_01.hints               |   4 +
 .../testMod.php                                    |  22 ++
 .../testMod.php.testModFix_01.fixed                |  22 ++
 .../testMod.php.testMod_01.hints                   |   4 +
 .../testMul.php                                    |  22 ++
 .../testMul.php.testMulFix_01.fixed                |  22 ++
 .../testMul.php.testMul_01.hints                   |   4 +
 .../testNoHints.php                                |  31 +++
 .../testNoHints.php.testNoHints_01.hints           |   1 +
 .../testNoHints.php.testNoHints_02.hints           |   1 +
 .../testNoHints.php.testNoHints_03.hints           |   1 +
 .../testNoHints.php.testNoHints_04.hints           |   1 +
 .../testNoHints.php.testNoHints_05.hints           |   1 +
 .../testNullCoalesce.php                           |  28 ++
 ...stNullCoalesce.php.testNullCoalesceFix_01.fixed |  28 ++
 ...stNullCoalesce.php.testNullCoalesceFix_02.fixed |  28 ++
 ...stNullCoalesce.php.testNullCoalesceFix_03.fixed |  28 ++
 .../testNullCoalesce.php.testNullCoalesce_01.hints |   4 +
 ...ullCoalesce.php.testNullCoalesce_01_php73.hints |   1 +
 .../testNullCoalesce.php.testNullCoalesce_02.hints |   4 +
 ...ullCoalesce.php.testNullCoalesce_02_php72.hints |   1 +
 .../testNullCoalesce.php.testNullCoalesce_03.hints |   4 +
 ...ullCoalesce.php.testNullCoalesce_03_php71.hints |   1 +
 .../testOr.php                                     |  22 ++
 .../testOr.php.testOrFix_01.fixed                  |  22 ++
 .../testOr.php.testOr_01.hints                     |   4 +
 .../testPlus.php                                   |  31 +++
 .../testPlus.php.testPlusFix_01.fixed              |  31 +++
 .../testPlus.php.testPlusFix_02.fixed              |  31 +++
 .../testPlus.php.testPlusFix_03.fixed              |  31 +++
 .../testPlus.php.testPlusFix_04.fixed              |  31 +++
 .../testPlus.php.testPlusFix_05.fixed              |  31 +++
 .../testPlus.php.testPlus_01.hints                 |   4 +
 .../testPlus.php.testPlus_01_php73.hints           |   4 +
 .../testPlus.php.testPlus_02.hints                 |   4 +
 .../testPlus.php.testPlus_03.hints                 |   4 +
 .../testPlus.php.testPlus_04.hints                 |   4 +
 .../testPlus.php.testPlus_05.hints                 |   4 +
 .../testPow.php                                    |  22 ++
 .../testPow.php.testPowFix_01.fixed                |  22 ++
 .../testPow.php.testPow_01.hints                   |   4 +
 .../testSl.php                                     |  22 ++
 .../testSl.php.testSlFix_01.fixed                  |  22 ++
 .../testSl.php.testSl_01.hints                     |   4 +
 .../testSr.php                                     |  22 ++
 .../testSr.php.testSrFix_01.fixed                  |  22 ++
 .../testSr.php.testSr_01.hints                     |   4 +
 .../testXor.php                                    |  22 ++
 .../testXor.php.testXorFix_01.fixed                |  22 ++
 .../testXor.php.testXor_01.hints                   |   4 +
 .../CombinedAssignmentOperatorSuggestionTest.java  | 241 +++++++++++++++++
 65 files changed, 1444 insertions(+), 3 deletions(-)

diff --git a/php/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/InfixExpression.java b/php/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/InfixExpression.java
index 29b5341..3643bb9 100644
--- a/php/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/InfixExpression.java
+++ b/php/php.editor/src/org/netbeans/modules/php/editor/parser/astnodes/InfixExpression.java
@@ -19,11 +19,14 @@
 package org.netbeans.modules.php.editor.parser.astnodes;
 
 /**
- * Represents an infix expression
- * <pre>e.g.<pre> $a + 1,
+ * Represents an infix expression.
+ * e.g.
+ * <pre>
+ * $a + 1,
  * 3 - 2,
  * foo() * $a->bar(),
  * 'string'.$c
+ * </pre>
  */
 public class InfixExpression extends Expression {
 
@@ -123,4 +126,3 @@ public class InfixExpression extends Expression {
     }
 
 }
-
diff --git a/php/php.editor/src/org/netbeans/modules/php/editor/resources/layer.xml b/php/php.editor/src/org/netbeans/modules/php/editor/resources/layer.xml
index bc7d72f..5817b0a 100644
--- a/php/php.editor/src/org/netbeans/modules/php/editor/resources/layer.xml
+++ b/php/php.editor/src/org/netbeans/modules/php/editor/resources/layer.xml
@@ -392,6 +392,7 @@
                     <file name="org-netbeans-modules-php-editor-verification-ArraySyntaxSuggestion.instance"/>
                     <file name="org-netbeans-modules-php-editor-verification-ArrowFunctionSuggestion.instance"/>
                     <file name="org-netbeans-modules-php-editor-verification-AssignVariableSuggestion.instance"/>
+                    <file name="org-netbeans-modules-php-editor-verification-CombinedAssignmentOperatorSuggestion.instance"/>
                     <file name="org-netbeans-modules-php-editor-verification-DeclareStrictTypesSuggestion.instance"/>
                     <file name="org-netbeans-modules-php-editor-verification-IdenticalComparisonSuggestion.instance"/>
                     <file name="org-netbeans-modules-php-editor-verification-InitializeFieldSuggestion.instance"/>
diff --git a/php/php.editor/src/org/netbeans/modules/php/editor/verification/CombinedAssignmentOperatorSuggestion.java b/php/php.editor/src/org/netbeans/modules/php/editor/verification/CombinedAssignmentOperatorSuggestion.java
new file mode 100644
index 0000000..cc3d9d9
--- /dev/null
+++ b/php/php.editor/src/org/netbeans/modules/php/editor/verification/CombinedAssignmentOperatorSuggestion.java
@@ -0,0 +1,296 @@
+/*
+ * 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.
+ */
+package org.netbeans.modules.php.editor.verification;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.netbeans.editor.BaseDocument;
+import org.netbeans.lib.editor.util.StringEscapeUtils;
+import org.netbeans.modules.csl.api.EditList;
+import org.netbeans.modules.csl.api.Hint;
+import org.netbeans.modules.csl.api.HintFix;
+import org.netbeans.modules.csl.api.OffsetRange;
+import org.netbeans.modules.csl.spi.support.CancelSupport;
+import org.netbeans.modules.php.api.PhpVersion;
+import org.netbeans.modules.php.editor.CodeUtils;
+import org.netbeans.modules.php.editor.parser.PHPParseResult;
+import org.netbeans.modules.php.editor.parser.astnodes.ASTNode;
+import org.netbeans.modules.php.editor.parser.astnodes.Assignment;
+import org.netbeans.modules.php.editor.parser.astnodes.ConditionalExpression;
+import org.netbeans.modules.php.editor.parser.astnodes.Expression;
+import org.netbeans.modules.php.editor.parser.astnodes.InfixExpression;
+import org.netbeans.modules.php.editor.parser.astnodes.ParenthesisExpression;
+import org.netbeans.modules.php.editor.parser.astnodes.VariableBase;
+import org.netbeans.modules.php.editor.parser.astnodes.visitors.DefaultVisitor;
+import org.openide.filesystems.FileObject;
+import org.openide.util.NbBundle;
+
+/**
+ * Suggest to use combind assignment operaotors.
+ *
+ * e.g.
+ * <pre>
+ * // + operator
+ * $x = $x + 100; // before
+ * $x += 100; // after
+ *
+ * // ?? operator
+ * $this->something->data['messages']['id'] = $this->something->data['messages']['id'] ?? "value";
+ * $this->something->data['messages']['id'] ??= "value";
+ * </pre>
+ */
+public class CombinedAssignmentOperatorSuggestion extends SuggestionRule {
+
+    private static final String HINT_ID = "Combined.Assignment.Operator.Suggestion"; // NOI18N
+
+    @Override
+    public String getId() {
+        return HINT_ID;
+    }
+
+    @Override
+    @NbBundle.Messages("CombinedAssignmentOperatorSuggestion.Description=Allows you to change to a combined assignment operator.")
+    public String getDescription() {
+        return Bundle.CombinedAssignmentOperatorSuggestion_Description();
+    }
+
+    @Override
+    @NbBundle.Messages("CombinedAssignmentOperatorSuggestion.DisplayName=Combined Assignment Operators")
+    public String getDisplayName() {
+        return Bundle.CombinedAssignmentOperatorSuggestion_DisplayName();
+    }
+
+    @Override
+    public void invoke(PHPRuleContext context, List<Hint> result) {
+        PHPParseResult phpParseResult = (PHPParseResult) context.parserResult;
+        if (phpParseResult.getProgram() == null) {
+            return;
+        }
+        if (CancelSupport.getDefault().isCancelled()) {
+            return;
+        }
+        final BaseDocument doc = context.doc;
+        int caretOffset = getCaretOffset();
+        OffsetRange lineBounds = VerificationUtils.createLineBounds(caretOffset, doc);
+        if (lineBounds.containsInclusive(caretOffset)) {
+            FileObject fileObject = phpParseResult.getSnapshot().getSource().getFileObject();
+            if (fileObject != null) {
+                CheckVisitor checkVisitor = new CheckVisitor(fileObject, this, context.doc, lineBounds);
+                phpParseResult.getProgram().accept(checkVisitor);
+                if (CancelSupport.getDefault().isCancelled()) {
+                    return;
+                }
+                result.addAll(checkVisitor.getHints());
+            }
+        }
+    }
+
+    protected PhpVersion getPhpVersion(FileObject fileObject) {
+        return CodeUtils.getPhpVersion(fileObject);
+    }
+
+    private boolean isAtLeastPhp74(FileObject fileObject) {
+        return getPhpVersion(fileObject).compareTo(PhpVersion.PHP_74) >= 0;
+    }
+
+    //~ inner classes
+    private static final class CheckVisitor extends DefaultVisitor {
+
+        private final FileObject fileObject;
+        private final CombinedAssignmentOperatorSuggestion suggestion;
+        private final BaseDocument document;
+        private final OffsetRange lineRange;
+        private final List<FixInfo> fixInfos = new ArrayList<>();
+
+        public CheckVisitor(FileObject fileObject, CombinedAssignmentOperatorSuggestion suggestion, BaseDocument document, OffsetRange lineRange) {
+            this.fileObject = fileObject;
+            this.suggestion = suggestion;
+            this.document = document;
+            this.lineRange = lineRange;
+        }
+
+        @NbBundle.Messages("CombinedAssignmentOperatorSuggestion.Hint.Description=You can use combined assignment operator")
+        public List<Hint> getHints() {
+            List<Hint> hints = new ArrayList<>();
+            for (FixInfo fixInfo : fixInfos) {
+                if (CancelSupport.getDefault().isCancelled()) {
+                    return Collections.emptyList();
+                }
+                hints.add(new Hint(suggestion, Bundle.CombinedAssignmentOperatorSuggestion_Hint_Description(), fileObject, lineRange, createFixes(fixInfo), 500));
+            }
+            return hints;
+        }
+
+        private List<HintFix> createFixes(FixInfo fixInfo) {
+            List<HintFix> hintFixes = new ArrayList<>();
+            hintFixes.add(fixInfo.createFix(document));
+            return hintFixes;
+        }
+
+        @Override
+        public void scan(ASTNode node) {
+            if (CancelSupport.getDefault().isCancelled()) {
+                return;
+            }
+            if (node != null && (VerificationUtils.isBefore(node.getStartOffset(), lineRange.getEnd()))) {
+                super.scan(node);
+            }
+        }
+
+        @Override
+        public void visit(Assignment node) {
+            if (CancelSupport.getDefault().isCancelled()) {
+                return;
+            }
+            OffsetRange nodeRange = new OffsetRange(node.getStartOffset(), node.getEndOffset());
+            if (lineRange.overlaps(nodeRange)) {
+                processAssignment(node);
+            }
+        }
+
+        private void processAssignment(Assignment node) {
+            Expression rightHandSide = node.getRightHandSide();
+            if (suggestion.isAtLeastPhp74(fileObject)
+                    && rightHandSide instanceof ConditionalExpression) {
+                // ?? operator
+                processConditionalExpression((ConditionalExpression) rightHandSide, node);
+            } else if (rightHandSide instanceof InfixExpression) {
+                // +, -, *, /, %, etc.
+                processInfixExpression((InfixExpression) rightHandSide, node);
+            }
+
+        }
+
+        private void processConditionalExpression(ConditionalExpression conditionalExpression, Assignment assignment) {
+            if (conditionalExpression.getOperator() == ConditionalExpression.OperatorType.COALESCE) {
+                Expression condition = conditionalExpression.getCondition();
+                addFixInfo(conditionalExpression.getOperator().toString(), condition, conditionalExpression.getIfFalse(), assignment);
+            }
+        }
+
+        private void processInfixExpression(InfixExpression infixExpression, Assignment assignment) {
+            if (isValidInfixExpressionOperator(infixExpression.getOperator())) {
+                Expression left = infixExpression.getLeft();
+                Expression right = infixExpression.getRight();
+                String operator = infixExpression.getOperator().toString();
+                // convert only simple infix expressions
+                // e.g. don't convert the following case
+                // $y = 10; $x = 5;
+                // $y = $y * $x + 3; // 53
+                // $y *= $x + 3; // 80
+                if (!(left instanceof InfixExpression)
+                        && !(right instanceof InfixExpression)
+                        && !(right instanceof ParenthesisExpression)) {
+                    addFixInfo(operator, left, right, assignment);
+                }
+            }
+        }
+
+        private void addFixInfo(String operator, Expression removalExpression, Expression removalEndExpression, Assignment assignment) {
+            VariableBase leftHandSide = assignment.getLeftHandSide();
+            if (removalExpression instanceof VariableBase
+                    && leftHandSide.toString().equals(removalExpression.toString())) { // compare them using another way? e.g use the lexer
+                int removalStart = leftHandSide.getEndOffset();
+                int removalEnd = removalEndExpression.getStartOffset();
+                fixInfos.add(new FixInfo(operator, new OffsetRange(removalStart, removalEnd)));
+            }
+        }
+
+        private static boolean isValidInfixExpressionOperator(InfixExpression.OperatorType operator) {
+            return operator == InfixExpression.OperatorType.PLUS
+                    || operator == InfixExpression.OperatorType.MINUS
+                    || operator == InfixExpression.OperatorType.MUL
+                    || operator == InfixExpression.OperatorType.DIV
+                    || operator == InfixExpression.OperatorType.CONCAT
+                    || operator == InfixExpression.OperatorType.MOD
+                    || operator == InfixExpression.OperatorType.SL
+                    || operator == InfixExpression.OperatorType.SR
+                    || operator == InfixExpression.OperatorType.AND
+                    || operator == InfixExpression.OperatorType.OR
+                    || operator == InfixExpression.OperatorType.XOR
+                    || operator == InfixExpression.OperatorType.POW;
+        }
+
+    }
+
+    private static final class FixInfo {
+
+        private final String operator;
+        private final OffsetRange removalOffsetRange;
+
+        public FixInfo(String operator, OffsetRange removingOffsetRange) {
+            this.operator = operator;
+            this.removalOffsetRange = removingOffsetRange;
+        }
+
+        public String getOperator() {
+            return operator;
+        }
+
+        public OffsetRange getRemovalOffsetRange() {
+            return removalOffsetRange;
+        }
+
+        public HintFix createFix(BaseDocument document) {
+            return new Fix(this, document);
+        }
+
+    }
+
+    private static final class Fix implements HintFix {
+
+        private final FixInfo fixInfo;
+        private final BaseDocument document;
+
+        private Fix(FixInfo fixInfo, BaseDocument document) {
+            this.fixInfo = fixInfo;
+            this.document = document;
+        }
+
+        @Override
+        @NbBundle.Messages({
+            "# {0} - combined operator",
+            "CombinedAssignmentOperatorSuggestion.Fix.Description=Use Combined Assignment Operator\"{0}\""
+        })
+        public String getDescription() {
+            // escape "<<"
+            return Bundle.CombinedAssignmentOperatorSuggestion_Fix_Description(StringEscapeUtils.escapeHtml(fixInfo.getOperator()) + "="); // NOI18N
+        }
+
+        @Override
+        public void implement() throws Exception {
+            EditList edits = new EditList(document);
+            OffsetRange removalOffsetRange = fixInfo.getRemovalOffsetRange();
+            String combinedOperator = String.format(" %s= ", fixInfo.getOperator()); // NOI18N
+            edits.replace(removalOffsetRange.getStart(), removalOffsetRange.getLength(), combinedOperator, true, 0);
+            edits.apply();
+        }
+
+        @Override
+        public boolean isSafe() {
+            return true;
+        }
+
+        @Override
+        public boolean isInteractive() {
+            return false;
+        }
+    }
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php
new file mode 100644
index 0000000..4e4e6d8
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x & 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php.testAndFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php.testAndFix_01.fixed
new file mode 100644
index 0000000..d9fb25a
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php.testAndFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x &= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php.testAnd_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php.testAnd_01.hints
new file mode 100644
index 0000000..dd94cd7
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testAnd.php.testAnd_01.hints
@@ -0,0 +1,4 @@
+$x = $x & ^10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"&amp;="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php
new file mode 100644
index 0000000..8653313
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x . 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php.testConcatFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php.testConcatFix_01.fixed
new file mode 100644
index 0000000..22e3876
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php.testConcatFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x .= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php.testConcat_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php.testConcat_01.hints
new file mode 100644
index 0000000..a5a2bb5
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testConcat.php.testConcat_01.hints
@@ -0,0 +1,4 @@
+$x = $x . 10^;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator".="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php
new file mode 100644
index 0000000..191c41e
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x / 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php.testDivFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php.testDivFix_01.fixed
new file mode 100644
index 0000000..346f87d
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php.testDivFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x /= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php.testDiv_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php.testDiv_01.hints
new file mode 100644
index 0000000..1819100
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testDiv.php.testDiv_01.hints
@@ -0,0 +1,4 @@
+$x = ^$x / 10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"/="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php
new file mode 100644
index 0000000..10f3bdc
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x - 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php.testMinusFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php.testMinusFix_01.fixed
new file mode 100644
index 0000000..e7f2fa1
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php.testMinusFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x -= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php.testMinus_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php.testMinus_01.hints
new file mode 100644
index 0000000..7d1a511
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMinus.php.testMinus_01.hints
@@ -0,0 +1,4 @@
+$x = $x -^ 10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"-="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php
new file mode 100644
index 0000000..d9ebba8
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x % 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php.testModFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php.testModFix_01.fixed
new file mode 100644
index 0000000..5461e86
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php.testModFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x %= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php.testMod_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php.testMod_01.hints
new file mode 100644
index 0000000..e8de058
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMod.php.testMod_01.hints
@@ -0,0 +1,4 @@
+$x = $x % 1^0;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"%="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php
new file mode 100644
index 0000000..d256bb4
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x * 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php.testMulFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php.testMulFix_01.fixed
new file mode 100644
index 0000000..c24a4fa
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php.testMulFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x *= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php.testMul_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php.testMul_01.hints
new file mode 100644
index 0000000..b399f29
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testMul.php.testMul_01.hints
@@ -0,0 +1,4 @@
+$x = $x * ^10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"*="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php
new file mode 100644
index 0000000..0dac86a
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x = $x + $y + 100;
+$x = $x + $y * 100;
+$x = ($x + $y) * 100;
+$x = $x / ($y * 100);
+$x = $x + getNumber() * 100;
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_01.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_01.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_02.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_02.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_02.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_03.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_03.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_03.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_04.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_04.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_04.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_05.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_05.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNoHints.php.testNoHints_05.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php
new file mode 100644
index 0000000..90b8d9b
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php
@@ -0,0 +1,28 @@
+<?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.
+ */
+
+// ?? null coalesce
+$test = $test ?? "test";
+$test = $test ?? getDefaultValue();
+$object->request['test']['id'] = $object->request['test']['id'] ?? "test";
+
+function getDefaultValue() {
+    return "default value";
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_01.fixed
new file mode 100644
index 0000000..7c31eb1
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_01.fixed
@@ -0,0 +1,28 @@
+<?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.
+ */
+
+// ?? null coalesce
+$test ??= "test";
+$test = $test ?? getDefaultValue();
+$object->request['test']['id'] = $object->request['test']['id'] ?? "test";
+
+function getDefaultValue() {
+    return "default value";
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_02.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_02.fixed
new file mode 100644
index 0000000..d94957a
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_02.fixed
@@ -0,0 +1,28 @@
+<?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.
+ */
+
+// ?? null coalesce
+$test = $test ?? "test";
+$test ??= getDefaultValue();
+$object->request['test']['id'] = $object->request['test']['id'] ?? "test";
+
+function getDefaultValue() {
+    return "default value";
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_03.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_03.fixed
new file mode 100644
index 0000000..aa9af5f
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesceFix_03.fixed
@@ -0,0 +1,28 @@
+<?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.
+ */
+
+// ?? null coalesce
+$test = $test ?? "test";
+$test = $test ?? getDefaultValue();
+$object->request['test']['id'] ??= "test";
+
+function getDefaultValue() {
+    return "default value";
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_01.hints
new file mode 100644
index 0000000..102c52b
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_01.hints
@@ -0,0 +1,4 @@
+$test = $tes^t ?? "test";
+------------------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"??="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_01_php73.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_01_php73.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_01_php73.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_02.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_02.hints
new file mode 100644
index 0000000..89c245b
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_02.hints
@@ -0,0 +1,4 @@
+$test = $test ?? getDefau^ltValue();
+-----------------------------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"??="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_02_php72.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_02_php72.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_02_php72.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_03.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_03.hints
new file mode 100644
index 0000000..0ef5591
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_03.hints
@@ -0,0 +1,4 @@
+$object->request['test']['id'] = $object->request['test']['id'] ??^ "test";
+--------------------------------------------------------------------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"??="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_03_php71.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_03_php71.hints
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testNullCoalesce.php.testNullCoalesce_03_php71.hints
@@ -0,0 +1 @@
+
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php
new file mode 100644
index 0000000..b8fab40
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x | 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php.testOrFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php.testOrFix_01.fixed
new file mode 100644
index 0000000..4000bb0
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php.testOrFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x |= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php.testOr_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php.testOr_01.hints
new file mode 100644
index 0000000..fccc076
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testOr.php.testOr_01.hints
@@ -0,0 +1,4 @@
+$x = ^$x | 10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"|="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php
new file mode 100644
index 0000000..050e1eb
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x = $x + 10;
+$x = $x + $y;
+$x = $x + (int)$y;
+$x = $x + getNumber();
+$x = $x + $object->request['messages']['id'];
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_01.fixed
new file mode 100644
index 0000000..a446941
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_01.fixed
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x += 10;
+$x = $x + $y;
+$x = $x + (int)$y;
+$x = $x + getNumber();
+$x = $x + $object->request['messages']['id'];
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_02.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_02.fixed
new file mode 100644
index 0000000..7c04f43
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_02.fixed
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x = $x + 10;
+$x += $y;
+$x = $x + (int)$y;
+$x = $x + getNumber();
+$x = $x + $object->request['messages']['id'];
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_03.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_03.fixed
new file mode 100644
index 0000000..78938f9
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_03.fixed
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x = $x + 10;
+$x = $x + $y;
+$x += (int)$y;
+$x = $x + getNumber();
+$x = $x + $object->request['messages']['id'];
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_04.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_04.fixed
new file mode 100644
index 0000000..e90c739
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_04.fixed
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x = $x + 10;
+$x = $x + $y;
+$x = $x + (int)$y;
+$x += getNumber();
+$x = $x + $object->request['messages']['id'];
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_05.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_05.fixed
new file mode 100644
index 0000000..c586307
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlusFix_05.fixed
@@ -0,0 +1,31 @@
+<?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.
+ */
+$x = 0;
+$y = 100;
+
+$x = $x + 10;
+$x = $x + $y;
+$x = $x + (int)$y;
+$x = $x + getNumber();
+$x += $object->request['messages']['id'];
+
+function getNumber(): int {
+    return 50;
+}
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_01.hints
new file mode 100644
index 0000000..6e18a6d
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_01.hints
@@ -0,0 +1,4 @@
+$x = $x + ^10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"+="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_01_php73.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_01_php73.hints
new file mode 100644
index 0000000..6e18a6d
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_01_php73.hints
@@ -0,0 +1,4 @@
+$x = $x + ^10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"+="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_02.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_02.hints
new file mode 100644
index 0000000..84a2acb
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_02.hints
@@ -0,0 +1,4 @@
+$x = ^$x + $y;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"+="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_03.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_03.hints
new file mode 100644
index 0000000..3670e83
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_03.hints
@@ -0,0 +1,4 @@
+$x = $x^ + (int)$y;
+------------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"+="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_04.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_04.hints
new file mode 100644
index 0000000..803b18b
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_04.hints
@@ -0,0 +1,4 @@
+$x = $x + getNumbe^r();
+----------------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"+="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_05.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_05.hints
new file mode 100644
index 0000000..a61c8ed
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPlus.php.testPlus_05.hints
@@ -0,0 +1,4 @@
+$x^ = $x + $object->request['messages']['id'];
+---------------------------------------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"+="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php
new file mode 100644
index 0000000..60653a7
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x ** 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php.testPowFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php.testPowFix_01.fixed
new file mode 100644
index 0000000..4a2fcdf
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php.testPowFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x **= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php.testPow_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php.testPow_01.hints
new file mode 100644
index 0000000..40fbccd
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testPow.php.testPow_01.hints
@@ -0,0 +1,4 @@
+$x = $x ** 10;^
+--------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"**="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php
new file mode 100644
index 0000000..eee80c0
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x << 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php.testSlFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php.testSlFix_01.fixed
new file mode 100644
index 0000000..d73c324
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php.testSlFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x <<= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php.testSl_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php.testSl_01.hints
new file mode 100644
index 0000000..69bea2b
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSl.php.testSl_01.hints
@@ -0,0 +1,4 @@
+$x = $x << 1^0;
+--------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"&lt;&lt;="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php
new file mode 100644
index 0000000..eba5d95
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x >> 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php.testSrFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php.testSrFix_01.fixed
new file mode 100644
index 0000000..a5bcb48
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php.testSrFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x >>= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php.testSr_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php.testSr_01.hints
new file mode 100644
index 0000000..cb83a3e
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testSr.php.testSr_01.hints
@@ -0,0 +1,4 @@
+$x^ = $x >> 10;
+--------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"&gt;&gt;="
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php
new file mode 100644
index 0000000..7e8f4a2
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x = $x ^ 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php.testXorFix_01.fixed b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php.testXorFix_01.fixed
new file mode 100644
index 0000000..a1cd84a
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php.testXorFix_01.fixed
@@ -0,0 +1,22 @@
+<?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.
+ */
+$x = 0;
+
+$x ^= 10;
diff --git a/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php.testXor_01.hints b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php.testXor_01.hints
new file mode 100644
index 0000000..40350ce
--- /dev/null
+++ b/php/php.editor/test/unit/data/testfiles/verification/CombinedAssignmentOperatorSuggestion/testXor.php.testXor_01.hints
@@ -0,0 +1,4 @@
+$x = $x ^^ 10;
+-------------
+HINT:You can use combined assignment operator
+FIX:Use Combined Assignment Operator"^="
diff --git a/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/verification/CombinedAssignmentOperatorSuggestionTest.java b/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/verification/CombinedAssignmentOperatorSuggestionTest.java
new file mode 100644
index 0000000..8765a49
--- /dev/null
+++ b/php/php.editor/test/unit/src/org/netbeans/modules/php/editor/verification/CombinedAssignmentOperatorSuggestionTest.java
@@ -0,0 +1,241 @@
+/*
+ * 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.
+ */
+package org.netbeans.modules.php.editor.verification;
+
+import org.netbeans.modules.php.api.PhpVersion;
+import org.openide.filesystems.FileObject;
+
+public class CombinedAssignmentOperatorSuggestionTest extends PHPHintsTestBase {
+
+    public CombinedAssignmentOperatorSuggestionTest(String testName) {
+        super(testName);
+    }
+
+    @Override
+    protected String getTestDirectory() {
+        return TEST_DIRECTORY + "CombinedAssignmentOperatorSuggestion/";
+    }
+
+    public void testNullCoalesce_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNullCoalesce.php", "$test = $tes^t ?? \"test\";");
+    }
+
+    public void testNullCoalesce_01_php73() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(PhpVersion.PHP_73), "testNullCoalesce.php", "$test = $tes^t ?? \"test\";");
+    }
+
+    public void testNullCoalesce_02() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNullCoalesce.php", "$test = $test ?? getDefau^ltValue();");
+    }
+
+    public void testNullCoalesce_02_php72() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(PhpVersion.PHP_72), "testNullCoalesce.php", "$test = $test ?? getDefau^ltValue();");
+    }
+
+    public void testNullCoalesce_03() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNullCoalesce.php", "$object->request['test']['id'] = $object->request['test']['id'] ??^ \"test\";");
+    }
+
+    public void testNullCoalesce_03_php71() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(PhpVersion.PHP_71), "testNullCoalesce.php", "$object->request['test']['id'] = $object->request['test']['id'] ??^ \"test\";");
+    }
+
+    public void testPlus_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = $x + ^10;");
+    }
+
+    public void testPlus_01_php73() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(PhpVersion.PHP_73), "testPlus.php", "$x = $x + ^10;");
+    }
+
+    public void testPlus_02() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = ^$x + $y;");
+    }
+
+    public void testPlus_03() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = $x^ + (int)$y;");
+    }
+
+    public void testPlus_04() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = $x + getNumbe^r();");
+    }
+
+    public void testPlus_05() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x^ = $x + $object->request['messages']['id'];");
+    }
+
+    public void testMinus_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testMinus.php", "$x = $x -^ 10;");
+    }
+
+    public void testMul_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testMul.php", "$x = $x * ^10;");
+    }
+
+    public void testDiv_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testDiv.php", "$x = ^$x / 10;");
+    }
+
+    public void testConcat_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testConcat.php", "$x = $x . 10^;");
+    }
+
+    public void testMod_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testMod.php", "$x = $x % 1^0;");
+    }
+
+    public void testSl_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testSl.php", "$x = $x << 1^0;");
+    }
+
+    public void testSr_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testSr.php", "$x^ = $x >> 10;");
+    }
+
+    public void testAnd_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testAnd.php", "$x = $x & ^10;");
+    }
+
+    public void testOr_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testOr.php", "$x = ^$x | 10;");
+    }
+
+    public void testXor_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testXor.php", "$x = $x ^^ 10;");
+    }
+
+    public void testPow_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testPow.php", "$x = $x ** 10;^");
+    }
+
+    public void testNoHints_01() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNoHints.php", "$x = $x + $y +^ 100;");
+    }
+
+    public void testNoHints_02() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNoHints.php", "$x = $x + $y * 100^;");
+    }
+
+    public void testNoHints_03() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNoHints.php", "$x = ^($x + $y) * 100;");
+    }
+
+    public void testNoHints_04() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNoHints.php", "$x = $x / ($y ^* 100);");
+    }
+
+    public void testNoHints_05() throws Exception {
+        checkHints(new CombinedAssignmentOperatorSuggestionStub(), "testNoHints.php", "$x^ = $x + getNumber() * 100;");
+    }
+
+    // Fixes
+    public void testNullCoalesceFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testNullCoalesce.php", "$test = $tes^t ?? \"test\";", "Use Combined Assignment Operator");
+    }
+
+    public void testNullCoalesceFix_02() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testNullCoalesce.php", "$test = $test ?? getDefau^ltValue();", "Use Combined Assignment Operator");
+    }
+
+    public void testNullCoalesceFix_03() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testNullCoalesce.php", "$object->request['test']['id'] = $object->request['test']['id'] ??^ \"test\";", "Use Combined Assignment Operator");
+    }
+
+    public void testPlusFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = $x + ^10;", "Use Combined Assignment Operator");
+    }
+
+    public void testPlusFix_02() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = ^$x + $y;", "Use Combined Assignment Operator");
+    }
+
+    public void testPlusFix_03() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = $x^ + (int)$y;", "Use Combined Assignment Operator");
+    }
+
+    public void testPlusFix_04() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x = $x + getNumbe^r();", "Use Combined Assignment Operator");
+    }
+
+    public void testPlusFix_05() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testPlus.php", "$x^ = $x + $object->request['messages']['id'];", "Use Combined Assignment Operator");
+    }
+
+    public void testMinusFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testMinus.php", "$x = $x -^ 10;", "Use Combined Assignment Operator");
+    }
+
+    public void testMulFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testMul.php", "$x = $x * ^10;", "Use Combined Assignment Operator");
+    }
+
+    public void testDivFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testDiv.php", "$x = ^$x / 10;", "Use Combined Assignment Operator");
+    }
+
+    public void testConcatFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testConcat.php", "$x = $x . 10^;", "Use Combined Assignment Operator");
+    }
+
+    public void testModFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testMod.php", "$x = $x % 1^0;", "Use Combined Assignment Operator");
+    }
+
+    public void testSlFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testSl.php", "$x = $x << 1^0;", "Use Combined Assignment Operator");
+    }
+
+    public void testSrFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testSr.php", "$x^ = $x >> 10;", "Use Combined Assignment Operator");
+    }
+
+    public void testAndFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testAnd.php", "$x = $x & ^10;", "Use Combined Assignment Operator");
+    }
+
+    public void testOrFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testOr.php", "$x = ^$x | 10;", "Use Combined Assignment Operator");
+    }
+
+    public void testXorFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testXor.php", "$x = $x ^^ 10;", "Use Combined Assignment Operator");
+    }
+
+    public void testPowFix_01() throws Exception {
+        applyHint(new CombinedAssignmentOperatorSuggestionStub(), "testPow.php", "$x = $x ** 10;^", "Use Combined Assignment Operator");
+    }
+
+    private static final class CombinedAssignmentOperatorSuggestionStub extends CombinedAssignmentOperatorSuggestion {
+
+        private final PhpVersion phpVersion;
+
+        public CombinedAssignmentOperatorSuggestionStub() {
+            this.phpVersion = PhpVersion.getDefault();
+        }
+
+        public CombinedAssignmentOperatorSuggestionStub(PhpVersion phpVersion) {
+            this.phpVersion = phpVersion;
+        }
+
+        @Override
+        protected PhpVersion getPhpVersion(FileObject fileObject) {
+            return phpVersion;
+        }
+    }
+}


---------------------------------------------------------------------
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