tntim96/JSCover

"this" in evaluated javascript is not correct

Closed this issue · 14 comments

e.g. I have this code snippet:

var functions = {
  func: function() {
    eval("this.style.height");
  }.bind(document.documentElement)
}

If I instrument it with the latest JSCover version, I get this:

_$jscoverage['/index.js'].lineData[1]++;
var functions = {func:function() {
  _$jscoverage['/index.js'].functionData[0]++;
  _$jscoverage['/index.js'].lineData[3]++;
  (0,eval)('this.style.height');
}.bind(document.documentElement)};

Unfortunately this.style.height triggers the script error "Cannot read property 'height' of undefined"

I think this is a closure compiler bug. I'll have to dig in to replicate using the command line and raise it there.

Hmmm java -jar ~/.m2/repository/com/google/javascript/closure-compiler/v20180402/closure-compiler-v20180402.jar --js test.js --language_in ECMASCRIPT_2017 --language_out ECMASCRIPT_2017 --formatting PRETTY_PRINT seems to work OK. Will have to debug to see what's the difference in print and/or parser options.

Comparing closure-compile config internals which work (1st line) with JSCover parser's which doesn't (2nd).

CompilerOptions{aggressiveFusion=false, aliasableStrings=[], aliasAllStrings=false, aliasHandler=com.google.javascript.jscomp.CompilerOptions$NullAliasTransformationHandler@2ea227af, aliasStringsBlacklist=, allowHotswapReplaceScript=false, ambiguateProperties=false, angularPass=false, anonymousFunctionNaming=OFF, appNameStr=, assumeClosuresOnlyCaptureReferences=false, assumeStrictThis=false, brokenClosureRequiresLevel=ERROR, checkDeterminism=false, checkGlobalNamesLevel=OFF, checkGlobalThisLevel=OFF, checkMissingGetCssNameLevel=OFF, checksOnly=false, checkSuspiciousCode=true,  checkSymbols=false, checkTypes=false, closurePass=true, coalesceVariableNames=true, codingConvention=com.google.javascript.jscomp.ClosureCodingConvention@7e7be63f, collapseAnonymousFunctions=false, collapseObjectLiterals=true, collapseProperties=NONE, collapseVariableDeclarations=true, colorizeErrorOutput=false, computeFunctionSideEffects=false, conformanceConfigs=[], continueAfterErrors=false, convertToDottedProperties=true, crossModuleCodeMotion=false, crossModuleCodeMotionNoStubMethods=false, crossModuleMethodMotion=false, dartPass=false, deadAssignmentElimination=true, declaredGlobalExternsOnWindow=true, defineReplacements={}, dependencyOptions=DependencyOptions{sortDependencies=true, pruneDependencies=false, dropMoochers=false, entryPoints=[]}, devirtualizePrototypeMethods=false, devMode=OFF, disambiguatePrivateProperties=false, disambiguateProperties=false, enforceAccessControlCodingConventions=false, environment=BROWSER, errorFormat=SINGLELINE, exportLocalPropertyDefinitions=false, exportTestFunctions=false, externExports=false, extraAnnotationNames=[], extractPrototypeMemberDeclarations=OFF, extraSmartNameRemoval=false, filesToPrintAfterEachPassRegexList=[], flowSensitiveInlineVariables=false, foldConstants=true, forceLibraryInjection=[], gatherCssNames=false, generateExportsAfterTypeChecking=true, generateExports=false, generatePseudoNames=false, generateTypedExterns=false, idGenerators={}, incrementalCheckMode=OFF, inferConsts=true, inferTypes=false, inlineConstantVars=false, inlineFunctionsLevel=LOCAL_ONLY, inlineGetters=false, inlineLocalVariables=true, inlineProperties=false, inlineVariables=false, inputDelimiter=// Input %num%, inputSourceMaps={}, instrumentationTemplateFile=, instrumentForCoverage=false, instrumentForCoverageOnly=false, instrumentBranchCoverage=false, j2clPassMode=AUTO, labelRenaming=true, languageIn=ECMASCRIPT_2017, languageOut=ECMASCRIPT_2017, legacyCodeCompile=false, lineBreak=false, lineLengthThreshold=500, markAsCompiled=false, markNoSideEffectCalls=false, maxFunctionSizeAfterInlining=-1, moduleRoots=[],   modulesToPrintAfterEachPassRegexList=[], moveFunctionDeclarations=false, nameGenerator=com.google.javascript.jscomp.DefaultNameGenerator@31304f14, optimizeArgumentsArray=true, optimizeCalls=false, outputCharset=US-ASCII, outputJs=NORMAL, outputJsStringUsage=false, parentModuleCanSeeSymbolsDeclaredInChildren=false, parseJsDocDocumentation=TYPES_ONLY, preferLineBreakAtEndOfFile=false, preferSingleQuotes=false, preferStableNames=false, preserveDetailedSourceInfo=false, preserveGoogProvidesAndRequires=false, preserveTypeAnnotations=false, prettyPrint=true, preventLibraryInjection=false, printConfig=false, printInputDelimiter=false, printSourceAfterEachPass=false, processCommonJSModules=false, transpileEs6ModulesToCjsModules=false, processObjectPropertyString=false, propertyInvalidationErrors={}, propertyRenaming=OFF, protectHiddenSideEffects=true, quoteKeywordProperties=false, recordFunctionInformation=false, removeAbstractMethods=false, removeSuperMethods=false, removeClosureAsserts=false, removeJ2clAsserts=true, removeDeadCode=true, removeUnusedClassProperties=false, removeUnusedConstructorProperties=false, removeUnusedLocalVars=true, removeUnusedPrototypePropertiesInExterns=false, removeUnusedPrototypeProperties=false, removeUnusedVars=false, renamePrefixNamespaceAssumeCrossModuleNames=false, replaceIdGenerators=false, replaceMessagesWithChromeI18n=false, replaceStringsFunctionDescriptions=[], replaceStringsPlaceholderToken=, replaceStringsReservedStrings=[], reserveRawExports=false, rewriteFunctionExpressions=false, rewritePolyfills=true,  runtimeTypeCheck=false, shadowVariables=true, skipNonTranspilationPasses=false, smartNameRemoval=false, sourceMapDetailLevel=ALL, sourceMapFormat=DEFAULT, sourceMapLocationMappings=[], stripNamePrefixes=[], stripNameSuffixes=[], stripTypePrefixes=[], stripTypes=[], summaryDetailLevel=1, tracer=OFF, transformAMDToCJSModules=false, trustedStrings=true, tweakProcessing=OFF, tweakReplacements={}, emitUseStrict=Optional.absent(), useTypesForLocalOptimization=false, variableRenaming=LOCAL, warningsGuard=DiagnosticGroup<checkVars>(OFF), DiagnosticGroup<es5Strict>(ERROR), com.google.javascript.jscomp.DiagnosticGroup@6f15d60e(OFF), DiagnosticGroup<nonStandardJsDocs>(OFF), wrapGoogModulesForWhitespaceOnly=true}
CompilerOptions{aggressiveFusion=false, aliasableStrings=[], aliasAllStrings=false, aliasHandler=com.google.javascript.jscomp.CompilerOptions$NullAliasTransformationHandler@7e0a8eeb, aliasStringsBlacklist=, allowHotswapReplaceScript=false, ambiguateProperties=false, angularPass=false, anonymousFunctionNaming=OFF, appNameStr=, assumeClosuresOnlyCaptureReferences=false, assumeStrictThis=false, brokenClosureRequiresLevel=ERROR, checkDeterminism=false, checkGlobalNamesLevel=OFF, checkGlobalThisLevel=OFF, checkMissingGetCssNameLevel=OFF, checksOnly=false, checkSuspiciousCode=false, checkSymbols=false, checkTypes=false, closurePass=true, coalesceVariableNames=true, codingConvention=com.google.javascript.jscomp.ClosureCodingConvention@70f69ac5, collapseAnonymousFunctions=false, collapseObjectLiterals=true, collapseProperties=NONE, collapseVariableDeclarations=true, colorizeErrorOutput=false, computeFunctionSideEffects=false, conformanceConfigs=[], continueAfterErrors=false, convertToDottedProperties=true, crossModuleCodeMotion=false, crossModuleCodeMotionNoStubMethods=false, crossModuleMethodMotion=false, dartPass=false, deadAssignmentElimination=true, declaredGlobalExternsOnWindow=true, defineReplacements={}, dependencyOptions=DependencyOptions{sortDependencies=true, pruneDependencies=false, dropMoochers=false, entryPoints=[]}, devirtualizePrototypeMethods=false, devMode=OFF, disambiguatePrivateProperties=false, disambiguateProperties=false, enforceAccessControlCodingConventions=false, environment=BROWSER, errorFormat=SINGLELINE, exportLocalPropertyDefinitions=false, exportTestFunctions=false, externExports=false,                          extractPrototypeMemberDeclarations=OFF, extraSmartNameRemoval=false, filesToPrintAfterEachPassRegexList=[], flowSensitiveInlineVariables=false, foldConstants=true, forceLibraryInjection=[], gatherCssNames=false, generateExportsAfterTypeChecking=true, generateExports=false, generatePseudoNames=false, generateTypedExterns=false, idGenerators={}, incrementalCheckMode=OFF, inferConsts=true, inferTypes=false, inlineConstantVars=false, inlineFunctionsLevel=LOCAL_ONLY, inlineGetters=false, inlineLocalVariables=true, inlineProperties=false, inlineVariables=false, inputDelimiter=// Input %num%, inputSourceMaps={}, instrumentationTemplateFile=, instrumentForCoverage=false, instrumentForCoverageOnly=false, instrumentBranchCoverage=false, j2clPassMode=AUTO, labelRenaming=true, languageIn=ECMASCRIPT_2017, languageOut=ECMASCRIPT_2017, legacyCodeCompile=false, lineBreak=false, lineLengthThreshold=500, markAsCompiled=false, markNoSideEffectCalls=false, maxFunctionSizeAfterInlining=-1, moduleRoots=[./], modulesToPrintAfterEachPassRegexList=[], moveFunctionDeclarations=false, nameGenerator=com.google.javascript.jscomp.DefaultNameGenerator@10096f5d, optimizeArgumentsArray=true, optimizeCalls=false,                         outputJs=NORMAL, outputJsStringUsage=false, parentModuleCanSeeSymbolsDeclaredInChildren=false, parseJsDocDocumentation=TYPES_ONLY, preferLineBreakAtEndOfFile=false, preferSingleQuotes=true,  preferStableNames=false, preserveDetailedSourceInfo=false, preserveGoogProvidesAndRequires=false, preserveTypeAnnotations=false, prettyPrint=true, preventLibraryInjection=false, printConfig=false, printInputDelimiter=false, printSourceAfterEachPass=false, processCommonJSModules=false, transpileEs6ModulesToCjsModules=false, processObjectPropertyString=false, propertyInvalidationErrors={}, propertyRenaming=OFF, protectHiddenSideEffects=true, quoteKeywordProperties=false, recordFunctionInformation=false, removeAbstractMethods=false, removeSuperMethods=false, removeClosureAsserts=false, removeJ2clAsserts=true, removeDeadCode=true, removeUnusedClassProperties=false, removeUnusedConstructorProperties=false, removeUnusedLocalVars=true, removeUnusedPrototypePropertiesInExterns=false, removeUnusedPrototypeProperties=false, removeUnusedVars=false, renamePrefixNamespaceAssumeCrossModuleNames=false, replaceIdGenerators=false, replaceMessagesWithChromeI18n=false, replaceStringsFunctionDescriptions=[], replaceStringsPlaceholderToken=, replaceStringsReservedStrings=[], reserveRawExports=false, rewriteFunctionExpressions=false, rewritePolyfills=false, runtimeTypeCheck=false, shadowVariables=true, skipNonTranspilationPasses=false, smartNameRemoval=false, sourceMapDetailLevel=ALL, sourceMapFormat=DEFAULT, sourceMapLocationMappings=[], stripNamePrefixes=[], stripNameSuffixes=[], stripTypePrefixes=[], stripTypes=[], summaryDetailLevel=1, tracer=OFF, transformAMDToCJSModules=false, trustedStrings=true, tweakProcessing=OFF, tweakReplacements={}, emitUseStrict=Optional.absent(), useTypesForLocalOptimization=false, variableRenaming=LOCAL, warningsGuard=,                                                                                                                                                                        wrapGoogModulesForWhitespaceOnly=true}
Config{languageMode=ECMASCRIPT8, strictMode=STRICT, jsDocParsingMode=TYPES_ONLY,                           runMode=STOP_AFTER_ERROR, annotations={ngInject=NG_INJECT, abstract=ABSTRACT, argument=PARAM, author=AUTHOR, consistentIdGenerator=CONSISTENTIDGENERATOR, const=CONSTANT, constant=CONSTANT, constructor=CONSTRUCTOR, customElement=CUSTOM_ELEMENT, copyright=LICENSE, define=DEFINE, deprecated=DEPRECATED, desc=DESC, dict=DICT, disposes=DISPOSES, enum=ENUM, export=EXPORT, expose=EXPOSE, extends=EXTENDS, externs=EXTERNS, fileoverview=FILE_OVERVIEW, final=FINAL, hidden=HIDDEN, idGenerator=IDGENERATOR, implements=IMPLEMENTS, implicitCast=IMPLICIT_CAST, inheritDoc=INHERIT_DOC, interface=INTERFACE, record=RECORD, lends=LENDS, license=LICENSE, meaning=MEANING, mixinClass=MIXIN_CLASS, mixinFunction=MIXIN_FUNCTION, modifies=MODIFIES, nocollapse=NO_COLLAPSE, nocompile=NO_COMPILE, noinline=NO_INLINE, nosideeffects=NO_SIDE_EFFECTS, override=OVERRIDE, owner=AUTHOR, package=PACKAGE, param=PARAM, polymer=POLYMER, polymerBehavior=POLYMER_BEHAVIOR, preserve=PRESERVE, private=PRIVATE, protected=PROTECTED, public=PUBLIC, return=RETURN, returns=RETURN, see=SEE, stableIdGenerator=STABLEIDGENERATOR, struct=STRUCT, suppress=SUPPRESS, template=TEMPLATE, this=THIS, throws=THROWS, type=TYPE, typedef=TYPEDEF, typeSummary=TYPE_SUMMARY, unrestricted=UNRESTRICTED, version=VERSION, wizaction=WIZACTION, exception=NOT_IMPLEMENTED, hassoydelcall=NOT_IMPLEMENTED, parent=NOT_IMPLEMENTED, usage=NOT_IMPLEMENTED, channel=NOT_IMPLEMENTED, methodOf=NOT_IMPLEMENTED, readonly=NOT_IMPLEMENTED, borrows=NOT_IMPLEMENTED, property=NOT_IMPLEMENTED, docsNotRequired=NOT_IMPLEMENTED, model=NOT_IMPLEMENTED, id=NOT_IMPLEMENTED, multiElement=NOT_IMPLEMENTED, element=NOT_IMPLEMENTED, method=NOT_IMPLEMENTED, module=NOT_IMPLEMENTED, eventType=NOT_IMPLEMENTED, priority=NOT_IMPLEMENTED, codepen=NOT_IMPLEMENTED, fires=NOT_IMPLEMENTED, field=NOT_IMPLEMENTED, preserveTry=NOT_IMPLEMENTED, mixes=NOT_IMPLEMENTED, requires=NOT_IMPLEMENTED, propertyOf=NOT_IMPLEMENTED, global=NOT_IMPLEMENTED, hassoydeltemplate=NOT_IMPLEMENTED, restrict=NOT_IMPLEMENTED, example=NOT_IMPLEMENTED, delegate=NOT_IMPLEMENTED, default=NOT_IMPLEMENTED, file=NOT_IMPLEMENTED, member=NOT_IMPLEMENTED, memberOf=NOT_IMPLEMENTED, event=NOT_IMPLEMENTED, url=NOT_IMPLEMENTED, todo=NOT_IMPLEMENTED, bug=NOT_IMPLEMENTED, docs-private=NOT_IMPLEMENTED, classdesc=NOT_IMPLEMENTED, wizmodule=NOT_IMPLEMENTED, config=NOT_IMPLEMENTED, augments=NOT_IMPLEMENTED, supported=NOT_IMPLEMENTED, wizSupportsSymbolicLookup=NOT_IMPLEMENTED, pintomodule=NOT_IMPLEMENTED, exportInterface=NOT_IMPLEMENTED, mods=NOT_IMPLEMENTED, instance=NOT_IMPLEMENTED, enhanceable=NOT_IMPLEMENTED, requirecss=NOT_IMPLEMENTED, function=NOT_IMPLEMENTED, static=NOT_IMPLEMENTED, visibility=NOT_IMPLEMENTED, kind=NOT_IMPLEMENTED, inner=NOT_IMPLEMENTED, mixin=NOT_IMPLEMENTED, name=NOT_IMPLEMENTED, modName=NOT_IMPLEMENTED, memberof=NOT_IMPLEMENTED, exec=NOT_IMPLEMENTED, since=NOT_IMPLEMENTED, virtual=NOT_IMPLEMENTED, addon=NOT_IMPLEMENTED, exportDoc=NOT_IMPLEMENTED, link=NOT_IMPLEMENTED, description=NOT_IMPLEMENTED, constructs=NOT_IMPLEMENTED, demo=NOT_IMPLEMENTED, noalias=NOT_IMPLEMENTED, animations=NOT_IMPLEMENTED, scope=NOT_IMPLEMENTED, alias=NOT_IMPLEMENTED, ignore=NOT_IMPLEMENTED, tutorial=NOT_IMPLEMENTED, class=NOT_IMPLEMENTED, enhance=NOT_IMPLEMENTED, summary=NOT_IMPLEMENTED, ngdoc=NOT_IMPLEMENTED, eventOf=NOT_IMPLEMENTED, namespace=NOT_IMPLEMENTED, provideGoog=NOT_IMPLEMENTED, base=NOT_IMPLEMENTED}, suppressionNames=[accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkEventfulObjectDisposal, checkRegExp, checkTypes, checkVars, closureDepMethodUsageChecks, const, constantProperty, deprecated, duplicate, es5Strict, externsValidation, extraProvide, extraRequire, fileoverviewTags, globalThis, invalidCasts, legacyGoogScopeRequire, lateProvide, lintChecks, messageConventions, misplacedTypeAnnotation, missingOverride, missingPolyfill, missingProperties, missingProvide, missingRequire, missingReturn, moduleLoad, newCheckTypes, newCheckTypesAllChecks, nonStandardJsDocs, reportUnknownTypes, strictCheckTypes, strictMissingProperties, strictModuleDepCheck, strictPrimitiveOperators, suspiciousCode, transitionalSuspiciousCodeWarnings, undefinedNames, undefinedVars, underscore, unknownDefines, unusedLocalVariables, unusedPrivateMembers, uselessCode, visibility, with], parseInlineSourceMaps=true}
Config{languageMode=ECMASCRIPT8, strictMode=SLOPPY, jsDocParsingMode=INCLUDE_DESCRIPTIONS_WITH_WHITESPACE, runMode=KEEP_GOING,       annotations={ngInject=NG_INJECT, abstract=ABSTRACT, argument=PARAM, author=AUTHOR, consistentIdGenerator=CONSISTENTIDGENERATOR, const=CONSTANT, constant=CONSTANT, constructor=CONSTRUCTOR, customElement=CUSTOM_ELEMENT, copyright=LICENSE, define=DEFINE, deprecated=DEPRECATED, desc=DESC, dict=DICT, disposes=DISPOSES, enum=ENUM, export=EXPORT, expose=EXPOSE, extends=EXTENDS, externs=EXTERNS, fileoverview=FILE_OVERVIEW, final=FINAL, hidden=HIDDEN, idGenerator=IDGENERATOR, implements=IMPLEMENTS, implicitCast=IMPLICIT_CAST, inheritDoc=INHERIT_DOC, interface=INTERFACE, record=RECORD, lends=LENDS, license=LICENSE, meaning=MEANING, mixinClass=MIXIN_CLASS, mixinFunction=MIXIN_FUNCTION, modifies=MODIFIES, nocollapse=NO_COLLAPSE, nocompile=NO_COMPILE, noinline=NO_INLINE, nosideeffects=NO_SIDE_EFFECTS, override=OVERRIDE, owner=AUTHOR, package=PACKAGE, param=PARAM, polymer=POLYMER, polymerBehavior=POLYMER_BEHAVIOR, preserve=PRESERVE, private=PRIVATE, protected=PROTECTED, public=PUBLIC, return=RETURN, returns=RETURN, see=SEE, stableIdGenerator=STABLEIDGENERATOR, struct=STRUCT, suppress=SUPPRESS, template=TEMPLATE, this=THIS, throws=THROWS, type=TYPE, typedef=TYPEDEF, typeSummary=TYPE_SUMMARY, unrestricted=UNRESTRICTED, version=VERSION, wizaction=WIZACTION, addon=NOT_IMPLEMENTED, alias=NOT_IMPLEMENTED, animations=NOT_IMPLEMENTED, augments=NOT_IMPLEMENTED, base=NOT_IMPLEMENTED, borrows=NOT_IMPLEMENTED, bug=NOT_IMPLEMENTED, channel=NOT_IMPLEMENTED, class=NOT_IMPLEMENTED, classdesc=NOT_IMPLEMENTED, codepen=NOT_IMPLEMENTED, config=NOT_IMPLEMENTED, constructs=NOT_IMPLEMENTED, default=NOT_IMPLEMENTED, delegate=NOT_IMPLEMENTED, demo=NOT_IMPLEMENTED, description=NOT_IMPLEMENTED, docsNotRequired=NOT_IMPLEMENTED, docs-private=NOT_IMPLEMENTED, element=NOT_IMPLEMENTED, enhance=NOT_IMPLEMENTED, enhanceable=NOT_IMPLEMENTED, event=NOT_IMPLEMENTED, eventOf=NOT_IMPLEMENTED, eventType=NOT_IMPLEMENTED, example=NOT_IMPLEMENTED, exception=NOT_IMPLEMENTED, exec=NOT_IMPLEMENTED, exportDoc=NOT_IMPLEMENTED, exportInterface=NOT_IMPLEMENTED, field=NOT_IMPLEMENTED, file=NOT_IMPLEMENTED, fires=NOT_IMPLEMENTED, function=NOT_IMPLEMENTED, global=NOT_IMPLEMENTED, hassoydelcall=NOT_IMPLEMENTED, hassoydeltemplate=NOT_IMPLEMENTED, id=NOT_IMPLEMENTED, ignore=NOT_IMPLEMENTED, inner=NOT_IMPLEMENTED, instance=NOT_IMPLEMENTED, kind=NOT_IMPLEMENTED, link=NOT_IMPLEMENTED, member=NOT_IMPLEMENTED, memberOf=NOT_IMPLEMENTED, memberof=NOT_IMPLEMENTED, method=NOT_IMPLEMENTED, methodOf=NOT_IMPLEMENTED, mixes=NOT_IMPLEMENTED, mixin=NOT_IMPLEMENTED, modName=NOT_IMPLEMENTED, model=NOT_IMPLEMENTED, mods=NOT_IMPLEMENTED, module=NOT_IMPLEMENTED, multiElement=NOT_IMPLEMENTED, name=NOT_IMPLEMENTED, namespace=NOT_IMPLEMENTED, ngdoc=NOT_IMPLEMENTED, noalias=NOT_IMPLEMENTED, parent=NOT_IMPLEMENTED, pintomodule=NOT_IMPLEMENTED, preserveTry=NOT_IMPLEMENTED, priority=NOT_IMPLEMENTED, property=NOT_IMPLEMENTED, propertyOf=NOT_IMPLEMENTED, provideGoog=NOT_IMPLEMENTED, readonly=NOT_IMPLEMENTED, requirecss=NOT_IMPLEMENTED, requires=NOT_IMPLEMENTED, restrict=NOT_IMPLEMENTED, scope=NOT_IMPLEMENTED, since=NOT_IMPLEMENTED, static=NOT_IMPLEMENTED, summary=NOT_IMPLEMENTED, supported=NOT_IMPLEMENTED, todo=NOT_IMPLEMENTED, tutorial=NOT_IMPLEMENTED, url=NOT_IMPLEMENTED, usage=NOT_IMPLEMENTED, virtual=NOT_IMPLEMENTED, visibility=NOT_IMPLEMENTED, wizSupportsSymbolicLookup=NOT_IMPLEMENTED, wizmodule=NOT_IMPLEMENTED}, suppressionNames=[accessControls, ambiguousFunctionDecl, checkDebuggerStatement, checkEventfulObjectDisposal, checkRegExp, checkTypes, checkVars, closureDepMethodUsageChecks, const, constantProperty, deprecated, duplicate, es5Strict, externsValidation, extraProvide, extraRequire, fileoverviewTags, globalThis, invalidCasts, legacyGoogScopeRequire, lateProvide, lintChecks, messageConventions, misplacedTypeAnnotation, missingOverride, missingPolyfill, missingProperties, missingProvide, missingRequire, missingReturn, moduleLoad, newCheckTypes, newCheckTypesAllChecks, nonStandardJsDocs, reportUnknownTypes, strictCheckTypes, strictMissingProperties, strictModuleDepCheck, strictPrimitiveOperators, suspiciousCode, transitionalSuspiciousCodeWarnings, undefinedNames, undefinedVars, underscore, unknownDefines, unusedLocalVariables, unusedPrivateMembers, uselessCode, visibility, with], parseInlineSourceMaps=false}

Hmmm. Still investigating. Here's what's in the patch and what I've tried with debugging:

  • Removed all instrumenting code from JSCover
  • Verify AST for modified JSCover and closure-compiler CLI is the same after parsing (via Node.toStringTree())
  • Verified all CodeGenerator options are the same before printing

What I've noticed that is different is that several external modules are loaded in the colsure-compiler CLI parser.

Match-cc-cli-props.patch.zip

Hello ! I'm facing the same issue using the last JSCover version (2.0.12). Can you give a status about this issue ? What is the last working version of JSCover ?

I just tested with closure-compiler v20211006, and still have the issue. I'll have to have another look into this. Version 2.0.12 is currently the latest version of JSCover.

The code @kaljak gave should be sufficient to reproduce. (0,eval) is not equivalent to eval especially for evaluating this (cf. https://stackoverflow.com/questions/9107240/1-evalthis-vs-evalthis-in-javascript) so final result is an error.

As soon as I use a JS code generator, these eval('this') appear really often in the instrumented code. I'm trying to find a closure-compiler CompilerOptions flag for this, but documentation is such a mess...

Edit : I confirm that using closure-compiler comand line eval is not substituted with (0,eval)

Working AST

jsRoot.toStringTree():
SCRIPT 1:0  [length: 106] [source_file: test.js] [feature_set: []]
    VAR 1:0  [length: 106] [source_file: test.js]
        NAME functions 1:4  [length: 102] [source_file: test.js]
            OBJECTLIT 1:16  [length: 90] [source_file: test.js]
                STRING_KEY func 2:2  [length: 4] [source_file: test.js]
                    CALL 2:8  [length: 78] [source_file: test.js]
                        GETPROP bind 4:4  [length: 4] [source_file: test.js]
                            FUNCTION  2:8  [length: 47] [source_file: test.js]
                                NAME  2:8  [length: 47] [source_file: test.js]
                                PARAM_LIST 2:16  [length: 2] [source_file: test.js]
                                BLOCK 2:19  [length: 36] [source_file: test.js]
                                    EXPR_RESULT 3:4  [length: 26] [source_file: test.js]
                                        CALL 3:4  [length: 25] [source_file: test.js]
                                            NAME eval 3:4  [length: 4] [source_file: test.js]
                                            STRINGLIT this.style.height 3:9  [length: 19] [source_file: test.js]
                        GETPROP documentElement 4:18  [length: 15] [source_file: test.js]
                            NAME document 4:9  [length: 8] [source_file: test.js]

Broken AST

SCRIPT 1:0  [length: 106] [source_file: test.js] [input_id: InputId: test.js] [feature_set: []]
    VAR 1:0  [length: 106] [source_file: test.js]
        NAME functions 1:4  [length: 102] [source_file: test.js] [constant_var_flags: 2]
            OBJECTLIT 1:16  [length: 90] [source_file: test.js]
                STRING_KEY func 2:2  [length: 4] [source_file: test.js]
                    CALL 2:8  [length: 78] [source_file: test.js]
                        GETPROP bind 4:4  [length: 4] [source_file: test.js]
                            FUNCTION  2:8  [length: 47] [source_file: test.js]
                                NAME  2:8  [length: 47] [source_file: test.js]
                                PARAM_LIST 2:16  [length: 2] [source_file: test.js]
                                BLOCK 2:19  [length: 36] [source_file: test.js]
                                    EXPR_RESULT 3:4  [length: 26] [source_file: test.js]
                                        CALL 3:4  [length: 25] [free_call: 1] [source_file: test.js]
                                            NAME eval 3:4  [length: 4] [direct_eval: 1] [source_file: test.js]
                                            STRINGLIT this.style.height 3:9  [length: 19] [source_file: test.js]
                        GETPROP documentElement 4:18  [length: 15] [source_file: test.js]
                            NAME document 4:9  [length: 8] [is_constant_name: 1] [source_file: test.js]

Can sort of fix by changing

    protected String instrumentSource(String sourceURI, String source) {
        SourceFile sourceFile = SourceFile.fromCode(sourceURI, source);
        ParserRunner.ParseResult parsed = parse(source, sourceFile);
        Node jsRoot = parsed.ast;
        commentsHandler.processComments(parsed.comments);

...to...

    protected String instrumentSource(String sourceURI, String source) {
        SourceFile sourceFile = SourceFile.fromCode(sourceURI, source);
        ErrorManager errorManager = new BlackHoleErrorManager();
        com.google.javascript.jscomp.Compiler compiler = new com.google.javascript.jscomp.Compiler(errorManager);
        Node jsRoot = compiler.parse(sourceFile);
//        commentsHandler.processComments(parsed.comments);

...but then I can't process the comments. I'm not sure how the compiler/parser is altered by this yet.

What I've seen debugging and searching in closure-compiler is that PrepareAst is never used by JSCover whereas it is by using Compiler.

PrepareAst is responsible for detecting if a call to eval is indirect or not in order to be changed to (0,eval) or not in CodeGenerator. As in you can see in your AST, it is responsible of the direct_eval: 1 causing eval not being replaced.

That's why your change make it work.

Yep - I noticed that too. Have you seen a way to turn that off using the ParserRunner?

I haven't searched more since I have to focus on another topic. I'll put some effort on that until next week and give you a status.

Maybe the solution is to use Compiler and get comments differently ? What is the reason comments are treated differently in JSCover ?

@tntim96 I've successfully solved the problem using Compiler. The harder part was to find the good options to keep the same behavior as before and get the comments. All test suite passes !

Please, review this pull request : #306

Looks good except for a few things:

  1. The JavaScript version configuration is ignored
  2. All tests for the above need to swap to the Compiler language mode
  3. The error reporter should use the logger (new LoggerErrorManager(logger))
  4. I'd need to review the branch integration tests which use the old parser code

I've fixed most of the above, but would like to merge your fix so you get the credit for your changes. I'll see if I can merge your commits to a branch, tidy up, then merge to the main branch.

Done - thanks @stephdz !