JS: Support TemplatePlaceholderTag.getEnclosingExpr

fixup! makeLocation
This commit is contained in:
Asger Feldthaus
2021-07-27 13:58:30 +02:00
parent 0a14de1741
commit 13aa511364
9 changed files with 80 additions and 44 deletions

View File

@@ -6,6 +6,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.Stack;
import java.util.regex.Matcher;
import com.semmle.js.ast.AClass;
import com.semmle.js.ast.AFunction;
@@ -570,6 +571,16 @@ public class ASTExtractor {
regexpExtractor.extract(source.substring(1, source.lastIndexOf('/')), offsets, nd, false);
} else if (nd.isStringLiteral() && !c.isInsideType() && nd.getRaw().length() < 1000) {
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;
}
@@ -2225,7 +2236,8 @@ public class ASTExtractor {
@Override
public Label visit(GeneratedCodeExpr nd, Context 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;
}
}

View File

@@ -39,7 +39,7 @@ public class HTMLExtractor implements IExtractor {
this.textualExtractor = textualExtractor;
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);
}
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(
TextualExtractor textualExtractor,
ScopeManager scopeManager,
@@ -407,9 +392,8 @@ public class HTMLExtractor implements IExtractor {
if (start >= end) return;
if (isEmbedded) return; // Do not extract template tags for HTML snippets embedded in a JS file
LocationManager locationManager = textualExtractor.getLocationManager();
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()) {
int startOffset = m.start();
int endOffset = m.end();
@@ -424,15 +408,12 @@ public class HTMLExtractor implements IExtractor {
String rawText = m.group();
trapwriter.addTuple("template_placeholder_tag_info", lbl, parentLabel.get(), rawText);
// Emit location
Position startPos = textualExtractor.getSourceMap().getStart(startOffset);
Position endPos = textualExtractor.getSourceMap().getEnd(endOffset - 1);
int endColumn = endPos.getColumn() - 1; // Convert to inclusive end position (still 1-based)
locationManager.emitFileLocation(
lbl, startPos.getLine(), startPos.getColumn(), endPos.getLine(), endColumn);
// Emit location entity
Label locationLbl = TemplateEngines.makeLocation(textualExtractor, startOffset, endOffset);
trapwriter.addTuple("hasLocation", lbl, locationLbl);
// 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()) {
// The body of the template tag is stored in the first capture group of each pattern
int bodyGroup = getNonNullCaptureGroup(m);

View File

@@ -103,12 +103,22 @@ public class ScopeManager {
private final ECMAVersion ecmaVersion;
private final Set<String> implicitGlobals = new LinkedHashSet<String>();
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.toplevelScope = enterScope(ScopeKind.GLOBAL, trapWriter.globalID("global_scope"), null);
this.ecmaVersion = ecmaVersion;
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;
}
/**

View File

@@ -77,7 +77,7 @@ public class ScriptExtractor implements IExtractor {
}
ScopeManager scopeManager =
new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion());
new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), false);
Label toplevelLabel = null;
LoCInfo loc;
try {

View File

@@ -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);
}
}

View File

@@ -23,7 +23,7 @@ public class TypeScriptExtractor implements IExtractor {
File sourceFile = textualExtractor.getExtractedFile();
Result res = state.getTypeScriptParser().parse(sourceFile, source, textualExtractor.getMetrics());
ScopeManager scopeManager =
new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017);
new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017, false);
try {
FileSnippet snippet = state.getSnippets().get(sourceFile.toPath());
SourceType sourceType = snippet != null ? snippet.getSourceType() : jsExtractor.establishSourceType(source, false);