Skip to content

Commit 0be0929

Browse files
authored
Merge pull request github#4958 from asgerf/js/angular2
Approved by erik-krogh
2 parents e4ed050 + d59ccb7 commit 0be0929

File tree

69 files changed

+37306
-1295
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+37306
-1295
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
lgtm,codescanning
2+
* Support for Angular has improved. Angular templates are now parsed and used to
3+
establish data flow between components.
4+
* Support for RxJS has improved. Taint is now tracked through RxJS Observable objects.
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package com.semmle.jcorn;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
import com.semmle.js.ast.AngularPipeRef;
7+
import com.semmle.js.ast.CallExpression;
8+
import com.semmle.js.ast.Expression;
9+
import com.semmle.js.ast.Identifier;
10+
import com.semmle.js.ast.Position;
11+
import com.semmle.js.ast.SourceLocation;
12+
import com.semmle.ts.ast.NonNullAssertion;
13+
14+
/**
15+
* Parser for Angular template expressions, based on the JS parser with
16+
* modified handling of the pipe operator.
17+
*/
18+
public class AngularExpressionParser extends CustomParser {
19+
public AngularExpressionParser(Options options, String input, int startPos) {
20+
super(options, input, startPos);
21+
}
22+
23+
@Override
24+
protected Expression buildBinary(
25+
int startPos,
26+
Position startLoc,
27+
Expression left,
28+
Expression right,
29+
String op,
30+
boolean logical) {
31+
// Angular pipe expression: `x|f:a` is desugared to `f(x, a)`
32+
if (op.equals("|")) {
33+
DestructuringErrors refDestructuringErrors = new DestructuringErrors();
34+
List<Expression> arguments = new ArrayList<>();
35+
arguments.add(left);
36+
while (this.type == TokenType.colon) {
37+
this.next();
38+
int argStartPos = this.pos;
39+
Position argStartLocation = this.curPosition();
40+
Expression arg = parseMaybeUnary(refDestructuringErrors, false);
41+
arguments.add(parseExprOp(arg, argStartPos, argStartLocation, TokenType.plusMin.binop, true));
42+
}
43+
SourceLocation loc = new SourceLocation(startLoc);
44+
if (right instanceof Identifier) {
45+
right = new AngularPipeRef(new SourceLocation(right.getLoc()), (Identifier)right);
46+
}
47+
return this.finishNode(new CallExpression(loc, right, new ArrayList<>(), arguments, false, false));
48+
}
49+
return super.buildBinary(startPos, startLoc, left, right, op, logical);
50+
}
51+
52+
@Override
53+
protected Expression parseExprAtom(DestructuringErrors refDestructuringErrors) {
54+
// Parse postfix "!" operator
55+
Position startLoc = this.startLoc;
56+
Expression expr = super.parseExprAtom(refDestructuringErrors);
57+
if (this.type == TokenType.prefix && "!".equals(this.value)) {
58+
this.next(); // consume "!" token
59+
return finishNode(new NonNullAssertion(new SourceLocation(startLoc), expr));
60+
}
61+
return expr;
62+
}
63+
}

javascript/extractor/src/com/semmle/jcorn/Parser.java

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,21 @@
33
import static com.semmle.jcorn.Whitespace.isNewLine;
44
import static com.semmle.jcorn.Whitespace.lineBreak;
55

6+
import java.io.File;
7+
import java.util.ArrayList;
8+
import java.util.LinkedHashMap;
9+
import java.util.LinkedHashSet;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.Objects;
13+
import java.util.Set;
14+
import java.util.Stack;
15+
import java.util.function.Function;
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
619
import com.semmle.jcorn.Identifiers.Dialect;
720
import com.semmle.jcorn.Options.AllowReserved;
8-
import com.semmle.jcorn.TokenType.Properties;
921
import com.semmle.js.ast.ArrayExpression;
1022
import com.semmle.js.ast.ArrayPattern;
1123
import com.semmle.js.ast.ArrowFunctionExpression;
@@ -45,7 +57,6 @@
4557
import com.semmle.js.ast.IPattern;
4658
import com.semmle.js.ast.Identifier;
4759
import com.semmle.js.ast.IfStatement;
48-
import com.semmle.js.ast.FieldDefinition;
4960
import com.semmle.js.ast.ImportDeclaration;
5061
import com.semmle.js.ast.ImportDefaultSpecifier;
5162
import com.semmle.js.ast.ImportNamespaceSpecifier;
@@ -95,18 +106,6 @@
95106
import com.semmle.util.exception.CatastrophicError;
96107
import com.semmle.util.exception.Exceptions;
97108
import com.semmle.util.io.WholeIO;
98-
import java.io.File;
99-
import java.util.ArrayList;
100-
import java.util.LinkedHashMap;
101-
import java.util.LinkedHashSet;
102-
import java.util.List;
103-
import java.util.Map;
104-
import java.util.Objects;
105-
import java.util.Set;
106-
import java.util.Stack;
107-
import java.util.function.Function;
108-
import java.util.regex.Matcher;
109-
import java.util.regex.Pattern;
110109

111110
/**
112111
* Java port of Acorn.
@@ -1462,7 +1461,7 @@ protected Expression parseExprOp(
14621461
return left;
14631462
}
14641463

1465-
private Expression buildBinary(
1464+
protected Expression buildBinary(
14661465
int startPos,
14671466
Position startLoc,
14681467
Expression left,
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.semmle.js.ast;
2+
3+
/**
4+
* An identifier occurring as the right operand of an Angular pipe expression,
5+
* which has been desugared to a function call with this expression as the callee.
6+
* <p>
7+
* For example, <code>x | f:y</code> is desugared to <code>f(x, y)</code> where the
8+
* <code>f</code> is an instance of {@link AngularPipeRef}, and evaluates to the function
9+
* being invoked.
10+
*/
11+
public class AngularPipeRef extends Expression {
12+
private final Identifier identifier;
13+
14+
public AngularPipeRef(SourceLocation loc, Identifier identifier) {
15+
super("AngularPipeRef", loc);
16+
this.identifier = identifier;
17+
}
18+
19+
@Override
20+
public <Q, A> A accept(Visitor<Q, A> v, Q q) {
21+
return v.visit(this, q);
22+
}
23+
24+
public Identifier getIdentifier() {
25+
return identifier;
26+
}
27+
}

javascript/extractor/src/com/semmle/js/ast/DefaultVisitor.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ public R visit(IFunction nd, C c) {
9393
else return visit((Expression) nd, c);
9494
}
9595

96+
@Override
97+
public R visit(AngularPipeRef nd, C c) {
98+
return visit((Expression) nd, c);
99+
}
100+
96101
@Override
97102
public R visit(AssignmentExpression nd, C c) {
98103
return visit((Expression) nd, c);

javascript/extractor/src/com/semmle/js/ast/NodeCopier.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package com.semmle.js.ast;
22

3+
import java.util.ArrayList;
4+
import java.util.List;
5+
36
import com.semmle.js.ast.jsx.JSXAttribute;
47
import com.semmle.js.ast.jsx.JSXClosingElement;
58
import com.semmle.js.ast.jsx.JSXElement;
@@ -48,8 +51,6 @@
4851
import com.semmle.ts.ast.UnaryTypeExpr;
4952
import com.semmle.ts.ast.UnionTypeExpr;
5053
import com.semmle.util.data.IntList;
51-
import java.util.ArrayList;
52-
import java.util.List;
5354

5455
/** Deep cloning of AST nodes. */
5556
public class NodeCopier implements Visitor<Void, INode> {
@@ -77,6 +78,11 @@ private IntList copy(IntList list) {
7778
return new IntList(list);
7879
}
7980

81+
@Override
82+
public INode visit(AngularPipeRef nd, Void q) {
83+
return new AngularPipeRef(nd.getLoc(), copy(nd.getIdentifier()));
84+
}
85+
8086
@Override
8187
public AssignmentExpression visit(AssignmentExpression nd, Void q) {
8288
return new AssignmentExpression(

javascript/extractor/src/com/semmle/js/ast/Position.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package com.semmle.js.ast;
22

3-
/** A source position identifying a single character. */
3+
/**
4+
* A source position identifying a single character.
5+
* <p>
6+
* Note that this class remains distinct from {@link com.semmle.util.locations.Position},
7+
* due to the 1-based line number convention and the tendency for users of this class to provide
8+
* dummy offset values. Although the classes are structurally identical, it is not always safe to
9+
* convert one into the other.
10+
*/
411
public class Position implements Comparable<Position> {
512
private final int line, column, offset;
613

@@ -23,6 +30,8 @@ public int getColumn() {
2330
/**
2431
* The offset (0-based) of this position from the start of the file, that is, the number of
2532
* characters that precede it.
33+
* <p>
34+
* Note that in some cases, a dummy value is filled in for the offset.
2635
*/
2736
public int getOffset() {
2837
return offset;

javascript/extractor/src/com/semmle/js/ast/Visitor.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
* <p>Visit methods take a context argument of type {@link C} and return a result of type {@link R}.
5555
*/
5656
public interface Visitor<C, R> {
57+
public R visit(AngularPipeRef nd, C q);
58+
5759
public R visit(AssignmentExpression nd, C q);
5860

5961
public R visit(AssignmentPattern nd, C q);

0 commit comments

Comments
 (0)