All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.javascript.jscomp.CheckSuspiciousCode Maven / Gradle / Ivy

There is a newer version: 9.0.8
Show newest version
/*
 * Copyright 2012 The Closure Compiler Authors.
 *
 * Licensed 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 com.google.javascript.jscomp;

import static com.google.common.base.Preconditions.checkState;

import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.rhino.Node;

/**
 * Checks for common errors, such as misplaced semicolons:
 * 
 * if (x); act_now();
 * 
* or comparison against NaN: *
 * if (x === NaN) act();
 * 
* and generates warnings. * * @author [email protected] (John Lenz) */ final class CheckSuspiciousCode extends AbstractPostOrderCallback { static final DiagnosticType SUSPICIOUS_SEMICOLON = DiagnosticType.warning( "JSC_SUSPICIOUS_SEMICOLON", "If this if/for/while really shouldn''t have a body, use '{}'"); static final DiagnosticType SUSPICIOUS_COMPARISON_WITH_NAN = DiagnosticType.warning( "JSC_SUSPICIOUS_NAN", "Comparison against NaN is always false. Did you mean isNaN()?"); static final DiagnosticType SUSPICIOUS_IN_OPERATOR = DiagnosticType.warning( "JSC_SUSPICIOUS_IN", "Use of the \"in\" keyword on non-object types throws an exception."); static final DiagnosticType SUSPICIOUS_INSTANCEOF_LEFT_OPERAND = DiagnosticType.warning( "JSC_SUSPICIOUS_INSTANCEOF_LEFT", "\"instanceof\" with left non-object operand is always false."); static final DiagnosticType SUSPICIOUS_NEGATED_LEFT_OPERAND_OF_IN_OPERATOR = DiagnosticType.warning( "JSC_SUSPICIOUS_NEGATED_LEFT_OPERAND_OF_IN_OPERATOR", "Suspicious negated left operand of 'in' operator."); @Override public void visit(NodeTraversal t, Node n, Node parent) { checkMissingSemicolon(t, n); checkNaN(t, n); checkInvalidIn(t, n); checkNonObjectInstanceOf(t, n); checkNegatedLeftOperandOfInOperator(t, n); } private void checkMissingSemicolon(NodeTraversal t, Node n) { switch (n.getToken()) { case IF: Node trueCase = n.getSecondChild(); reportIfWasEmpty(t, trueCase); Node elseCase = trueCase.getNext(); if (elseCase != null) { reportIfWasEmpty(t, elseCase); } break; case WHILE: case FOR: case FOR_IN: case FOR_OF: reportIfWasEmpty(t, NodeUtil.getLoopCodeBlock(n)); break; default: break; } } private static void reportIfWasEmpty(NodeTraversal t, Node block) { checkState(block.isNormalBlock()); // A semicolon is distinguished from a block without children by // annotating it with EMPTY_BLOCK. Blocks without children are // usually intentional, especially with loops. if (!block.hasChildren() && block.isAddedBlock()) { t.getCompiler().report( t.makeError(block, SUSPICIOUS_SEMICOLON)); } } private void checkNaN(NodeTraversal t, Node n) { switch (n.getToken()) { case EQ: case GE: case GT: case LE: case LT: case NE: case SHEQ: case SHNE: reportIfNaN(t, n.getFirstChild()); reportIfNaN(t, n.getLastChild()); break; default: break; } } private static void reportIfNaN(NodeTraversal t, Node n) { if (NodeUtil.isNaN(n)) { t.getCompiler().report( t.makeError(n.getParent(), SUSPICIOUS_COMPARISON_WITH_NAN)); } } private void checkInvalidIn(NodeTraversal t, Node n) { if (n.isIn()) { reportIfNonObject(t, n.getLastChild(), SUSPICIOUS_IN_OPERATOR); } } private void checkNonObjectInstanceOf(NodeTraversal t, Node n) { if (n.isInstanceOf()) { reportIfNonObject( t, n.getFirstChild(), SUSPICIOUS_INSTANCEOF_LEFT_OPERAND); } } private static boolean reportIfNonObject( NodeTraversal t, Node n, DiagnosticType diagnosticType) { if (n.isAdd() || !NodeUtil.mayBeObject(n)) { t.report(n.getParent(), diagnosticType); return true; } return false; } private void checkNegatedLeftOperandOfInOperator(NodeTraversal t, Node n) { if (n.isIn() && n.getFirstChild().isNot()) { t.report(n.getFirstChild(), SUSPICIOUS_NEGATED_LEFT_OPERAND_OF_IN_OPERATOR); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy