mirror of
https://github.com/github/codeql.git
synced 2025-12-21 19:26:31 +01:00
JS: Support TemplatePlaceholderTag.getEnclosingExpr
fixup! makeLocation
This commit is contained in:
@@ -6,6 +6,7 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
import com.semmle.js.ast.AClass;
|
import com.semmle.js.ast.AClass;
|
||||||
import com.semmle.js.ast.AFunction;
|
import com.semmle.js.ast.AFunction;
|
||||||
@@ -570,6 +571,16 @@ public class ASTExtractor {
|
|||||||
regexpExtractor.extract(source.substring(1, source.lastIndexOf('/')), offsets, nd, false);
|
regexpExtractor.extract(source.substring(1, source.lastIndexOf('/')), offsets, nd, false);
|
||||||
} else if (nd.isStringLiteral() && !c.isInsideType() && nd.getRaw().length() < 1000) {
|
} else if (nd.isStringLiteral() && !c.isInsideType() && nd.getRaw().length() < 1000) {
|
||||||
regexpExtractor.extract(valueString, makeStringLiteralOffsets(nd.getRaw()), nd, true);
|
regexpExtractor.extract(valueString, makeStringLiteralOffsets(nd.getRaw()), nd, true);
|
||||||
|
|
||||||
|
// Scan the string for template tags, if we're in a context where such tags are relevant.
|
||||||
|
if (scopeManager.isInTemplateFile()) {
|
||||||
|
Matcher m = TemplateEngines.TEMPLATE_TAGS.matcher(nd.getRaw());
|
||||||
|
int offset = nd.getLoc().getStart().getOffset();
|
||||||
|
while (m.find()) {
|
||||||
|
Label locationLbl = TemplateEngines.makeLocation(lexicalExtractor.getTextualExtractor(), offset + m.start(), offset + m.end());
|
||||||
|
trapwriter.addTuple("expr_contains_template_tag_location", key, locationLbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@@ -2225,7 +2236,8 @@ public class ASTExtractor {
|
|||||||
@Override
|
@Override
|
||||||
public Label visit(GeneratedCodeExpr nd, Context c) {
|
public Label visit(GeneratedCodeExpr nd, Context c) {
|
||||||
Label key = super.visit(nd, c);
|
Label key = super.visit(nd, c);
|
||||||
trapwriter.addTuple("generated_code_expr_info", key, nd.getOpeningDelimiter(), nd.getClosingDelimiter(), nd.getBody());
|
Label templateLbl = TemplateEngines.makeLocation(lexicalExtractor.getTextualExtractor(), nd.getLoc().getStart().getOffset(), nd.getLoc().getEnd().getOffset());
|
||||||
|
trapwriter.addTuple("expr_contains_template_tag_location", key, templateLbl);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class HTMLExtractor implements IExtractor {
|
|||||||
this.textualExtractor = textualExtractor;
|
this.textualExtractor = textualExtractor;
|
||||||
|
|
||||||
this.scopeManager =
|
this.scopeManager =
|
||||||
new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion());
|
new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -382,21 +382,6 @@ public class HTMLExtractor implements IExtractor {
|
|||||||
writer.addTuple("toplevel_parent_xml_node", topLevelLabel, htmlNodeLabel);
|
writer.addTuple("toplevel_parent_xml_node", topLevelLabel, htmlNodeLabel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String MUSTACHE_TAG_DOUBLE = "\\{\\{(?!\\{)(.*?)\\}\\}"; // {{ x }}
|
|
||||||
private static final String MUSTACHE_TAG_TRIPLE = "\\{\\{\\{(.*?)\\}\\}\\}"; // {{{ x }}}
|
|
||||||
private static final String MUSTACHE_TAG_PERCENT = "\\{%(?!>)(.*?)%\\}"; // {% x %}
|
|
||||||
private static final String EJS_TAG = "<%(?![%<>}])[-=]?(.*?)[_-]?%>"; // <% x %>
|
|
||||||
|
|
||||||
/** Pattern for a template tag whose contents should be parsed as an expression */
|
|
||||||
private static final Pattern TEMPLATE_EXPR_OPENING_TAG =
|
|
||||||
Pattern.compile("^(?:\\{\\{\\{?|<%[-=])"); // {{, {{{, <%=, <%-
|
|
||||||
|
|
||||||
private static final Pattern TEMPLATE_TAGS =
|
|
||||||
Pattern.compile(
|
|
||||||
StringUtil.glue(
|
|
||||||
"|", MUSTACHE_TAG_DOUBLE, MUSTACHE_TAG_TRIPLE, MUSTACHE_TAG_PERCENT, EJS_TAG),
|
|
||||||
Pattern.DOTALL);
|
|
||||||
|
|
||||||
private void extractTemplateTags(
|
private void extractTemplateTags(
|
||||||
TextualExtractor textualExtractor,
|
TextualExtractor textualExtractor,
|
||||||
ScopeManager scopeManager,
|
ScopeManager scopeManager,
|
||||||
@@ -407,9 +392,8 @@ public class HTMLExtractor implements IExtractor {
|
|||||||
if (start >= end) return;
|
if (start >= end) return;
|
||||||
if (isEmbedded) return; // Do not extract template tags for HTML snippets embedded in a JS file
|
if (isEmbedded) return; // Do not extract template tags for HTML snippets embedded in a JS file
|
||||||
|
|
||||||
LocationManager locationManager = textualExtractor.getLocationManager();
|
|
||||||
TrapWriter trapwriter = textualExtractor.getTrapwriter();
|
TrapWriter trapwriter = textualExtractor.getTrapwriter();
|
||||||
Matcher m = TEMPLATE_TAGS.matcher(textualExtractor.getSource()).region(start, end);
|
Matcher m = TemplateEngines.TEMPLATE_TAGS.matcher(textualExtractor.getSource()).region(start, end);
|
||||||
while (m.find()) {
|
while (m.find()) {
|
||||||
int startOffset = m.start();
|
int startOffset = m.start();
|
||||||
int endOffset = m.end();
|
int endOffset = m.end();
|
||||||
@@ -424,15 +408,12 @@ public class HTMLExtractor implements IExtractor {
|
|||||||
String rawText = m.group();
|
String rawText = m.group();
|
||||||
trapwriter.addTuple("template_placeholder_tag_info", lbl, parentLabel.get(), rawText);
|
trapwriter.addTuple("template_placeholder_tag_info", lbl, parentLabel.get(), rawText);
|
||||||
|
|
||||||
// Emit location
|
// Emit location entity
|
||||||
Position startPos = textualExtractor.getSourceMap().getStart(startOffset);
|
Label locationLbl = TemplateEngines.makeLocation(textualExtractor, startOffset, endOffset);
|
||||||
Position endPos = textualExtractor.getSourceMap().getEnd(endOffset - 1);
|
trapwriter.addTuple("hasLocation", lbl, locationLbl);
|
||||||
int endColumn = endPos.getColumn() - 1; // Convert to inclusive end position (still 1-based)
|
|
||||||
locationManager.emitFileLocation(
|
|
||||||
lbl, startPos.getLine(), startPos.getColumn(), endPos.getLine(), endColumn);
|
|
||||||
|
|
||||||
// Parse the contents as a template expression, if the delimiter expects an expression.
|
// Parse the contents as a template expression, if the delimiter expects an expression.
|
||||||
Matcher delimMatcher = TEMPLATE_EXPR_OPENING_TAG.matcher(rawText);
|
Matcher delimMatcher = TemplateEngines.TEMPLATE_EXPR_OPENING_TAG.matcher(rawText);
|
||||||
if (delimMatcher.find()) {
|
if (delimMatcher.find()) {
|
||||||
// The body of the template tag is stored in the first capture group of each pattern
|
// The body of the template tag is stored in the first capture group of each pattern
|
||||||
int bodyGroup = getNonNullCaptureGroup(m);
|
int bodyGroup = getNonNullCaptureGroup(m);
|
||||||
|
|||||||
@@ -103,12 +103,22 @@ public class ScopeManager {
|
|||||||
private final ECMAVersion ecmaVersion;
|
private final ECMAVersion ecmaVersion;
|
||||||
private final Set<String> implicitGlobals = new LinkedHashSet<String>();
|
private final Set<String> implicitGlobals = new LinkedHashSet<String>();
|
||||||
private Scope implicitVariableScope;
|
private Scope implicitVariableScope;
|
||||||
|
private final boolean isInTemplateScope;
|
||||||
|
|
||||||
public ScopeManager(TrapWriter trapWriter, ECMAVersion ecmaVersion) {
|
public ScopeManager(TrapWriter trapWriter, ECMAVersion ecmaVersion, boolean isInTemplateScope) {
|
||||||
this.trapWriter = trapWriter;
|
this.trapWriter = trapWriter;
|
||||||
this.toplevelScope = enterScope(ScopeKind.GLOBAL, trapWriter.globalID("global_scope"), null);
|
this.toplevelScope = enterScope(ScopeKind.GLOBAL, trapWriter.globalID("global_scope"), null);
|
||||||
this.ecmaVersion = ecmaVersion;
|
this.ecmaVersion = ecmaVersion;
|
||||||
this.implicitVariableScope = toplevelScope;
|
this.implicitVariableScope = toplevelScope;
|
||||||
|
this.isInTemplateScope = isInTemplateScope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true the current scope is potentially in a template file, and may contain
|
||||||
|
* relevant template tags.
|
||||||
|
*/
|
||||||
|
public boolean isInTemplateFile() {
|
||||||
|
return isInTemplateScope;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class ScriptExtractor implements IExtractor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ScopeManager scopeManager =
|
ScopeManager scopeManager =
|
||||||
new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion());
|
new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), false);
|
||||||
Label toplevelLabel = null;
|
Label toplevelLabel = null;
|
||||||
LoCInfo loc;
|
LoCInfo loc;
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package com.semmle.js.extractor;
|
||||||
|
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import com.semmle.util.data.StringUtil;
|
||||||
|
import com.semmle.util.locations.Position;
|
||||||
|
import com.semmle.util.trap.TrapWriter.Label;
|
||||||
|
|
||||||
|
public class TemplateEngines {
|
||||||
|
private static final String MUSTACHE_TAG_TRIPLE = "\\{\\{\\{(.*?)\\}\\}\\}"; // {{{ x }}}
|
||||||
|
private static final String MUSTACHE_TAG_DOUBLE = "\\{\\{(?!\\{)(.*?)\\}\\}"; // {{ x }}}
|
||||||
|
private static final String MUSTACHE_TAG_PERCENT = "\\{%(?!>)(.*?)%\\}"; // {% x %}
|
||||||
|
private static final String EJS_TAG = "<%(?![%<>}])[-=]?(.*?)[_-]?%>"; // <% x %>
|
||||||
|
|
||||||
|
/** Pattern for a template tag whose contents should be parsed as an expression */
|
||||||
|
public static final Pattern TEMPLATE_EXPR_OPENING_TAG =
|
||||||
|
Pattern.compile("^(?:\\{\\{\\{?|<%[-=])"); // {{, {{{, <%=, <%-
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pattern matching a template tag from a supported template engine.
|
||||||
|
*/
|
||||||
|
public static final Pattern TEMPLATE_TAGS =
|
||||||
|
Pattern.compile(
|
||||||
|
StringUtil.glue(
|
||||||
|
"|", TemplateEngines.MUSTACHE_TAG_DOUBLE, MUSTACHE_TAG_TRIPLE, MUSTACHE_TAG_PERCENT, EJS_TAG),
|
||||||
|
Pattern.DOTALL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the location label for a template tag at the given offsets.
|
||||||
|
*/
|
||||||
|
public static Label makeLocation(TextualExtractor extractor, int startOffset, int endOffset) {
|
||||||
|
Position startPos = extractor.getSourceMap().getStart(startOffset);
|
||||||
|
Position endPos = extractor.getSourceMap().getEnd(endOffset - 1);
|
||||||
|
int endColumn = endPos.getColumn() - 1; // Convert to inclusive end position (still 1-based)
|
||||||
|
return extractor.getLocationManager().emitLocationsDefault(startPos.getLine(), startPos.getColumn(), endPos.getLine(), endColumn);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@ public class TypeScriptExtractor implements IExtractor {
|
|||||||
File sourceFile = textualExtractor.getExtractedFile();
|
File sourceFile = textualExtractor.getExtractedFile();
|
||||||
Result res = state.getTypeScriptParser().parse(sourceFile, source, textualExtractor.getMetrics());
|
Result res = state.getTypeScriptParser().parse(sourceFile, source, textualExtractor.getMetrics());
|
||||||
ScopeManager scopeManager =
|
ScopeManager scopeManager =
|
||||||
new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017);
|
new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017, false);
|
||||||
try {
|
try {
|
||||||
FileSnippet snippet = state.getSnippets().get(sourceFile.toPath());
|
FileSnippet snippet = state.getSnippets().get(sourceFile.toPath());
|
||||||
SourceType sourceType = snippet != null ? snippet.getSourceType() : jsExtractor.establishSourceType(source, false);
|
SourceType sourceType = snippet != null ? snippet.getSourceType() : jsExtractor.establishSourceType(source, false);
|
||||||
|
|||||||
@@ -2893,18 +2893,9 @@ class ImportMetaExpr extends @import_meta_expr, Expr {
|
|||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
class GeneratedCodeExpr extends @generated_code_expr, Expr {
|
class GeneratedCodeExpr extends @generated_code_expr, Expr {
|
||||||
/** Gets the opening delimiter, such as `{{` or `{{{`. */
|
|
||||||
string getOpeningDelimiter() { generated_code_expr_info(this, result, _, _) }
|
|
||||||
|
|
||||||
/** Gets the closing delimiter, such as `}}` or `}}}`. */
|
|
||||||
string getClosingDelimiter() { generated_code_expr_info(this, _, result, _) }
|
|
||||||
|
|
||||||
/** Gets the text between the delimiters, including any surrounding whitespace, such as the `x` in `{{x}}`. */
|
|
||||||
string getBody() { generated_code_expr_info(this, _, _, result) }
|
|
||||||
|
|
||||||
/** Gets the placeholder tag that was parsed as an expression. */
|
/** Gets the placeholder tag that was parsed as an expression. */
|
||||||
Templating::TemplatePlaceholderTag getPlaceholderTag() {
|
Templating::TemplatePlaceholderTag getPlaceholderTag() {
|
||||||
result.getLocation() = this.getLocation()
|
this = result.getEnclosingExpr()
|
||||||
}
|
}
|
||||||
|
|
||||||
override string getAPrimaryQlClass() { result = "GeneratedCodeExpr" }
|
override string getAPrimaryQlClass() { result = "GeneratedCodeExpr" }
|
||||||
|
|||||||
@@ -114,6 +114,13 @@ module Templating {
|
|||||||
* that is, without being enclosed in a string literal or similar.
|
* that is, without being enclosed in a string literal or similar.
|
||||||
*/
|
*/
|
||||||
predicate isInPlainCodeContext() { this = any(GeneratedCodeExpr e).getPlaceholderTag() }
|
predicate isInPlainCodeContext() { this = any(GeneratedCodeExpr e).getPlaceholderTag() }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the innermost JavaScript expression containing this template tag, if any.
|
||||||
|
*/
|
||||||
|
Expr getEnclosingExpr() {
|
||||||
|
expr_contains_template_tag_location(result, getLocation())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -417,11 +417,9 @@ case @expr.kind of
|
|||||||
@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector;
|
@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector;
|
||||||
@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident;
|
@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident;
|
||||||
|
|
||||||
generated_code_expr_info(
|
expr_contains_template_tag_location(
|
||||||
unique int expr: @generated_code_expr ref,
|
int expr: @expr ref,
|
||||||
varchar(900) openingDelimiter: string ref,
|
int location: @location ref
|
||||||
varchar(900) closingDelimiter: string ref,
|
|
||||||
varchar(900) body: string ref
|
|
||||||
);
|
);
|
||||||
|
|
||||||
@template_placeholder_tag_parent = @xmlelement | @xmlattribute | @file;
|
@template_placeholder_tag_parent = @xmlelement | @xmlattribute | @file;
|
||||||
|
|||||||
Reference in New Issue
Block a user