This is an automated email from the ASF dual-hosted git repository. joshtynjala pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/royale-compiler.git
commit 6d569104b1c94fef1b86d6ce285ae0fda533f729 Author: Josh Tynjala <[email protected]> AuthorDate: Mon Sep 26 14:48:36 2022 -0700 linter: vars-on-top --- .../main/java/org/apache/royale/linter/LINTER.java | 4 + .../apache/royale/linter/config/Configuration.java | 16 ++++ .../royale/linter/rules/VariablesOnTopRule.java | 89 ++++++++++++++++++++++ 3 files changed, 109 insertions(+) diff --git a/linter/src/main/java/org/apache/royale/linter/LINTER.java b/linter/src/main/java/org/apache/royale/linter/LINTER.java index 09d6442a0..1cb85902d 100644 --- a/linter/src/main/java/org/apache/royale/linter/LINTER.java +++ b/linter/src/main/java/org/apache/royale/linter/LINTER.java @@ -88,6 +88,7 @@ import org.apache.royale.linter.rules.ThisInClosureRule; import org.apache.royale.linter.rules.TraceRule; import org.apache.royale.linter.rules.UnsafeNegationRule; import org.apache.royale.linter.rules.ValidTypeofRule; +import org.apache.royale.linter.rules.VariablesOnTopRule; import org.apache.royale.linter.rules.WildcardImportRule; import org.apache.royale.linter.rules.WithRule; import org.apache.royale.utils.FilenameNormalization; @@ -374,6 +375,9 @@ public class LINTER { if (configuration.getValidTypeof()) { rules.add(new ValidTypeofRule()); } + if (configuration.getVarsOnTop()) { + rules.add(new VariablesOnTopRule()); + } if (configuration.getWildcardImport()) { rules.add(new WildcardImportRule()); } diff --git a/linter/src/main/java/org/apache/royale/linter/config/Configuration.java b/linter/src/main/java/org/apache/royale/linter/config/Configuration.java index 1faa79e85..9459b370a 100644 --- a/linter/src/main/java/org/apache/royale/linter/config/Configuration.java +++ b/linter/src/main/java/org/apache/royale/linter/config/Configuration.java @@ -858,6 +858,22 @@ public class Configuration { this.validTypeof = b; } + // + // 'vars-on-top' option + // + + private boolean varsOnTop = false; + + public boolean getVarsOnTop() { + return varsOnTop; + } + + @Config + @Mapping("vars-on-top") + public void setVarsOnTop(ConfigurationValue cv, boolean b) { + this.varsOnTop = b; + } + // // 'wildcard-import' option // diff --git a/linter/src/main/java/org/apache/royale/linter/rules/VariablesOnTopRule.java b/linter/src/main/java/org/apache/royale/linter/rules/VariablesOnTopRule.java new file mode 100644 index 000000000..a6ae31f94 --- /dev/null +++ b/linter/src/main/java/org/apache/royale/linter/rules/VariablesOnTopRule.java @@ -0,0 +1,89 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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.apache.royale.linter.rules; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import org.apache.royale.compiler.problems.CompilerProblem; +import org.apache.royale.compiler.problems.ICompilerProblem; +import org.apache.royale.compiler.tree.ASTNodeID; +import org.apache.royale.compiler.tree.as.IASNode; +import org.apache.royale.compiler.tree.as.IFunctionNode; +import org.apache.royale.compiler.tree.as.IScopedNode; +import org.apache.royale.compiler.tree.as.IVariableNode; +import org.apache.royale.linter.LinterRule; +import org.apache.royale.linter.NodeVisitor; +import org.apache.royale.linter.TokenQuery; + +/** + * Check that variables are always declared at the top of a function. + */ +public class VariablesOnTopRule extends LinterRule { + @Override + public Map<ASTNodeID, NodeVisitor> getNodeVisitors() { + Map<ASTNodeID, NodeVisitor> result = new HashMap<>(); + result.put(ASTNodeID.FunctionID, (node, tokenQuery, problems) -> { + checkFunctionNode((IFunctionNode) node, tokenQuery, problems); + }); + return result; + } + + private void checkFunctionNode(IFunctionNode functionNode, TokenQuery tokenQuery, Collection<ICompilerProblem> problems) { + IScopedNode scopedNode = functionNode.getScopedNode(); + if (scopedNode == null) { + return; + } + boolean afterNonVariable = false; + for (int i = 0; i < scopedNode.getChildCount(); i++) { + IASNode child = scopedNode.getChild(i); + afterNonVariable = checkVariablesNotAtTop(child, afterNonVariable, problems); + } + } + + private boolean checkVariablesNotAtTop(IASNode node, boolean afterNonVariable, Collection<ICompilerProblem> problems) { + if (node instanceof IVariableNode) { + IVariableNode variableNode = (IVariableNode) node; + if (afterNonVariable) { + problems.add(new VariablesOnTopLinterProblem(variableNode)); + } + return afterNonVariable; + } + afterNonVariable = true; + for (int i = 0; i < node.getChildCount(); i++) { + IASNode child = node.getChild(i); + afterNonVariable = checkVariablesNotAtTop(child, afterNonVariable, problems); + } + return afterNonVariable; + } + + public static class VariablesOnTopLinterProblem extends CompilerProblem { + public static final String DESCRIPTION = "Variable name '${varName}' must be declared at the top of this function"; + + public VariablesOnTopLinterProblem(IVariableNode node) + { + super(node.getNameExpressionNode()); + varName = node.getName(); + } + + public String varName; + } +}
