From 2e858db848cc09bb87c4ee3f89198d4691ca38b0 Mon Sep 17 00:00:00 2001 From: Asger F Date: Thu, 19 May 2022 15:05:23 +0200 Subject: [PATCH] JS: Declare variables from ambient declarations fixup --- .../semmle/js/extractor/HTMLExtractor.java | 5 +-- .../com/semmle/js/extractor/ScopeManager.java | 36 +++++++++++++------ .../semmle/js/extractor/ScriptExtractor.java | 2 +- .../js/extractor/TypeScriptExtractor.java | 6 ++-- 4 files changed, 34 insertions(+), 15 deletions(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java index 664d898d5e1..a03d03bfe0c 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/HTMLExtractor.java @@ -40,7 +40,8 @@ public class HTMLExtractor implements IExtractor { this.textualExtractor = textualExtractor; this.scopeManager = - new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), true); + new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), + ScopeManager.FileKind.TEMPLATE); } /* @@ -425,7 +426,7 @@ public class HTMLExtractor implements IExtractor { extractSnippet( TopLevelKind.ANGULAR_STYLE_TEMPLATE, config.withSourceType(SourceType.ANGULAR_STYLE_TEMPLATE), - new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2020, true), + new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2020, ScopeManager.FileKind.TEMPLATE), textualExtractor, m.group(bodyGroup), m.start(bodyGroup), diff --git a/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java b/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java index 81bdc9e6f92..e7306e77e01 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ScopeManager.java @@ -97,20 +97,31 @@ public class ScopeManager { } } + public static enum FileKind { + /** Any file not specific to one of the other file kinds. */ + PLAIN, + + /** A file potentially containing template tags. */ + TEMPLATE, + + /** A d.ts file, containing TypeScript ambient declarations. */ + TYPESCRIPT_DECLARATION, + } + private final TrapWriter trapWriter; private Scope curScope; private final Scope toplevelScope; private final ECMAVersion ecmaVersion; private final Set implicitGlobals = new LinkedHashSet(); private Scope implicitVariableScope; - private final boolean isInTemplateScope; + private final FileKind fileKind; - public ScopeManager(TrapWriter trapWriter, ECMAVersion ecmaVersion, boolean isInTemplateScope) { + public ScopeManager(TrapWriter trapWriter, ECMAVersion ecmaVersion, FileKind fileKind) { this.trapWriter = trapWriter; this.toplevelScope = enterScope(ScopeKind.GLOBAL, trapWriter.globalID("global_scope"), null); this.ecmaVersion = ecmaVersion; - this.implicitVariableScope = toplevelScope; - this.isInTemplateScope = isInTemplateScope; + this.implicitVariableScope = toplevelScope; + this.fileKind = fileKind; } /** @@ -118,7 +129,11 @@ public class ScopeManager { * relevant template tags. */ public boolean isInTemplateFile() { - return isInTemplateScope; + return this.fileKind == FileKind.TEMPLATE; + } + + public boolean isInTypeScriptDeclarationFile() { + return this.fileKind == FileKind.TYPESCRIPT_DECLARATION; } /** @@ -221,7 +236,7 @@ public class ScopeManager { /** * Get the label for a given variable in the current scope; if it cannot be found, add it to the - * implicit variable scope (usually the global scope). + * implicit variable scope (usually the global scope). */ public Label getVarKey(String name) { Label lbl = curScope.lookupVariable(name); @@ -411,7 +426,7 @@ public class ScopeManager { // cases where we turn on the 'declKind' flags @Override public Void visit(FunctionDeclaration nd, Void v) { - if (nd.hasDeclareKeyword()) return null; + if (nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile()) return null; // strict mode functions are block-scoped, non-strict mode ones aren't if (blockscope == isStrict) visit(nd.getId(), DeclKind.var); return null; @@ -419,7 +434,7 @@ public class ScopeManager { @Override public Void visit(ClassDeclaration nd, Void c) { - if (nd.hasDeclareKeyword()) return null; + if (nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile()) return null; if (blockscope) visit(nd.getClassDef().getId(), DeclKind.varAndType); return null; } @@ -468,7 +483,7 @@ public class ScopeManager { @Override public Void visit(VariableDeclaration nd, Void v) { - if (nd.hasDeclareKeyword()) return null; + if (nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile()) return null; // in block scoping mode, only process 'let'; in non-block scoping // mode, only process non-'let' if (blockscope == nd.isBlockScoped(ecmaVersion)) visit(nd.getDeclarations()); @@ -503,7 +518,8 @@ public class ScopeManager { @Override public Void visit(NamespaceDeclaration nd, Void c) { if (blockscope) return null; - boolean hasVariable = nd.isInstantiated() && !nd.hasDeclareKeyword(); + boolean isAmbientOutsideDtsFile = nd.hasDeclareKeyword() && !isInTypeScriptDeclarationFile(); + boolean hasVariable = nd.isInstantiated() && !isAmbientOutsideDtsFile; visit(nd.getName(), hasVariable ? DeclKind.varAndNamespace : DeclKind.namespace); return null; } diff --git a/javascript/extractor/src/com/semmle/js/extractor/ScriptExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/ScriptExtractor.java index 08d29d98a9b..b4b47a786f9 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/ScriptExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/ScriptExtractor.java @@ -77,7 +77,7 @@ public class ScriptExtractor implements IExtractor { } ScopeManager scopeManager = - new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), false); + new ScopeManager(textualExtractor.getTrapwriter(), config.getEcmaVersion(), ScopeManager.FileKind.PLAIN); Label toplevelLabel = null; LoCInfo loc; try { diff --git a/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java index 629abccb422..623c6ec7fc8 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/TypeScriptExtractor.java @@ -22,8 +22,10 @@ public class TypeScriptExtractor implements IExtractor { String source = textualExtractor.getSource(); File sourceFile = textualExtractor.getExtractedFile(); Result res = state.getTypeScriptParser().parse(sourceFile, source, textualExtractor.getMetrics()); - ScopeManager scopeManager = - new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017, false); + ScopeManager.FileKind fileKind = sourceFile.getName().endsWith(".d.ts") + ? ScopeManager.FileKind.TYPESCRIPT_DECLARATION + : ScopeManager.FileKind.PLAIN; + ScopeManager scopeManager = new ScopeManager(textualExtractor.getTrapwriter(), ECMAVersion.ECMA2017, fileKind); try { FileSnippet snippet = state.getSnippets().get(sourceFile.toPath()); SourceType sourceType = snippet != null ? snippet.getSourceType() : jsExtractor.establishSourceType(source, false);