Loading lib/jsduck/function_ast.rb +37 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ module JsDuck "undefined" elsif this?(ast) :this elsif boolean?(ast) "Boolean" else :other end Loading @@ -90,6 +92,26 @@ module JsDuck ast["type"] == "ThisExpression" end def boolean?(ast) if boolean_literal?(ast) true elsif ast["type"] == "UnaryExpression" || ast["type"] == "BinaryExpression" !!BOOLEAN_RETURNING_OPERATORS[ast["operator"]] elsif ast["type"] == "LogicalExpression" boolean?(ast["left"]) && boolean?(ast["right"]) elsif ast["type"] == "ConditionalExpression" boolean?(ast["consequent"]) && boolean?(ast["alternate"]) elsif ast["type"] == "AssignmentExpression" && ast["operator"] == "=" boolean?(ast["right"]) else false end end def boolean_literal?(ast) ast["type"] == "Literal" && (ast["value"] == true || ast["value"] == false) end def control_flow?(ast) CONTROL_FLOW[ast["type"]] end Loading Loading @@ -118,6 +140,21 @@ module JsDuck end end BOOLEAN_RETURNING_OPERATORS = { "!" => true, ">" => true, ">=" => true, "<" => true, "<=" => true, "==" => true, "!=" => true, "===" => true, "!==" => true, "in" => true, "instanceof" => true, "delete" => true, } POSSIBLY_BLOCKING = { "IfStatement" => true, "DoWhileStatement" => true, Loading spec/function_ast_spec.rb +54 −0 Original line number Diff line number Diff line Loading @@ -231,4 +231,58 @@ describe "JsDuck::FunctionAst#return_types" do end end describe "returns ['Boolean'] when function body" do it "returns true" do returns("/** */ function foo() { return true; }").should == ["Boolean"] end it "returns false" do returns("/** */ function foo() { return false; }").should == ["Boolean"] end it "returns negation" do returns("/** */ function foo() { return !foo; }").should == ["Boolean"] end it "returns > comparison" do returns("/** */ function foo() { return x > y; }").should == ["Boolean"] end it "returns <= comparison" do returns("/** */ function foo() { return x <= y; }").should == ["Boolean"] end it "returns == comparison" do returns("/** */ function foo() { return x == y; }").should == ["Boolean"] end it "returns 'in' expression" do returns("/** */ function foo() { return key in object; }").should == ["Boolean"] end it "returns 'instanceof' expression" do returns("/** */ function foo() { return obj instanceof cls; }").should == ["Boolean"] end it "returns 'delete' expression" do returns("/** */ function foo() { return delete foo[bar]; }").should == ["Boolean"] end it "returns conjunction of boolean expressions" do returns("/** */ function foo() { return x > y && y > z; }").should == ["Boolean"] end it "returns disjunction of boolean expressions" do returns("/** */ function foo() { return x == y || y == z; }").should == ["Boolean"] end it "returns conditional expression evaluating to boolean" do returns("/** */ function foo() { return x ? true : a > b; }").should == ["Boolean"] end it "returns assignment of boolean" do returns("/** */ function foo() { return x = true; }").should == ["Boolean"] end end end Loading
lib/jsduck/function_ast.rb +37 −0 Original line number Diff line number Diff line Loading @@ -73,6 +73,8 @@ module JsDuck "undefined" elsif this?(ast) :this elsif boolean?(ast) "Boolean" else :other end Loading @@ -90,6 +92,26 @@ module JsDuck ast["type"] == "ThisExpression" end def boolean?(ast) if boolean_literal?(ast) true elsif ast["type"] == "UnaryExpression" || ast["type"] == "BinaryExpression" !!BOOLEAN_RETURNING_OPERATORS[ast["operator"]] elsif ast["type"] == "LogicalExpression" boolean?(ast["left"]) && boolean?(ast["right"]) elsif ast["type"] == "ConditionalExpression" boolean?(ast["consequent"]) && boolean?(ast["alternate"]) elsif ast["type"] == "AssignmentExpression" && ast["operator"] == "=" boolean?(ast["right"]) else false end end def boolean_literal?(ast) ast["type"] == "Literal" && (ast["value"] == true || ast["value"] == false) end def control_flow?(ast) CONTROL_FLOW[ast["type"]] end Loading Loading @@ -118,6 +140,21 @@ module JsDuck end end BOOLEAN_RETURNING_OPERATORS = { "!" => true, ">" => true, ">=" => true, "<" => true, "<=" => true, "==" => true, "!=" => true, "===" => true, "!==" => true, "in" => true, "instanceof" => true, "delete" => true, } POSSIBLY_BLOCKING = { "IfStatement" => true, "DoWhileStatement" => true, Loading
spec/function_ast_spec.rb +54 −0 Original line number Diff line number Diff line Loading @@ -231,4 +231,58 @@ describe "JsDuck::FunctionAst#return_types" do end end describe "returns ['Boolean'] when function body" do it "returns true" do returns("/** */ function foo() { return true; }").should == ["Boolean"] end it "returns false" do returns("/** */ function foo() { return false; }").should == ["Boolean"] end it "returns negation" do returns("/** */ function foo() { return !foo; }").should == ["Boolean"] end it "returns > comparison" do returns("/** */ function foo() { return x > y; }").should == ["Boolean"] end it "returns <= comparison" do returns("/** */ function foo() { return x <= y; }").should == ["Boolean"] end it "returns == comparison" do returns("/** */ function foo() { return x == y; }").should == ["Boolean"] end it "returns 'in' expression" do returns("/** */ function foo() { return key in object; }").should == ["Boolean"] end it "returns 'instanceof' expression" do returns("/** */ function foo() { return obj instanceof cls; }").should == ["Boolean"] end it "returns 'delete' expression" do returns("/** */ function foo() { return delete foo[bar]; }").should == ["Boolean"] end it "returns conjunction of boolean expressions" do returns("/** */ function foo() { return x > y && y > z; }").should == ["Boolean"] end it "returns disjunction of boolean expressions" do returns("/** */ function foo() { return x == y || y == z; }").should == ["Boolean"] end it "returns conditional expression evaluating to boolean" do returns("/** */ function foo() { return x ? true : a > b; }").should == ["Boolean"] end it "returns assignment of boolean" do returns("/** */ function foo() { return x = true; }").should == ["Boolean"] end end end