@@ -195,15 +195,26 @@ public int getCoveredRegularFunc() {
195195 return coveredRegularFunc ;
196196 }
197197
198+ // DOM Access Coverage
199+ private ArrayList <Integer > coveredDOMAccessLines = new ArrayList <Integer >();
200+ public ArrayList <Integer > getCoveredDOMAccessLines () {
201+ return coveredDOMAccessLines ;
202+ }
203+ private ArrayList <Integer > missedDOMAccessLines = new ArrayList <Integer >();
204+ public ArrayList <Integer > getMissedDOMAccessLines () {
205+ return missedDOMAccessLines ;
206+ }
207+
208+
209+
198210 private int missedRegularFunc = 0 ;
199-
200- private String testsFramework ;
201-
202211 public int getMissedRegularFunc () {
203212 return missedRegularFunc ;
204213 }
205214
215+ private String testsFramework ;
206216
217+
207218 public void setVisitOnly (String visitOnly ){
208219 this .visitOnly = visitOnly ;
209220 }
@@ -559,6 +570,18 @@ private void analyzeProductionCodeFunctionCallNode(AstNode node) {
559570 if (!functionCalls .contains (targetSource ))
560571 functionCalls .add (targetSource );
561572
573+ // check for DOM API accessing the DOM
574+ if (isDOMAPIMethod (targetSource )){
575+ int lineNumber = node .getLineno ()+1 ;
576+ if (coveredStatementLines .contains (lineNumber )){
577+ if (!coveredDOMAccessLines .contains (lineNumber )) coveredDOMAccessLines .add (lineNumber );
578+ System .out .println ("======== Covered DOM access at line" + (node .getLineno ()+1 ) + " - DOM access: " + targetSource );
579+ }else {
580+ if (!missedDOMAccessLines .contains (lineNumber )) missedDOMAccessLines .add (lineNumber );
581+ System .out .println ("======== Missed DOM access at line" + (node .getLineno ()+1 ) + " - DOM access: " + targetSource );
582+ }
583+ }
584+
562585 // check for callback and if it's an event-dependent callback
563586 for (AstNode n : fcall .getArguments ()){
564587 if (n .shortName ().equals ("Name" ) && coveredFunctions .contains (n .toSource ())){
@@ -605,8 +628,18 @@ private void analyzeProductionCodeAssignmentNode(AstNode node) {
605628 missedEventCallback ++;
606629 }
607630 //System.out.println("Event-dependent callback function: " + asmt.toSource());
608- }
609631
632+ }else // checking for DOM element changes
633+ if (isDOMElementAttribute (varName )){
634+ int lineNumber = node .getLineno ()+1 ;
635+ if (coveredStatementLines .contains (lineNumber )){
636+ if (!coveredDOMAccessLines .contains (lineNumber )) coveredDOMAccessLines .add (lineNumber );
637+ System .out .println ("======== Covered DOM access at line" + (node .getLineno ()+1 ) + " - DOM elem attribute: " + varName );
638+ }else {
639+ if (!missedDOMAccessLines .contains (lineNumber )) missedDOMAccessLines .add (lineNumber );
640+ System .out .println ("======== Missed DOM access at line" + (node .getLineno ()+1 ) + " - DOM elem attribute: " + varName );
641+ }
642+ }
610643 }
611644
612645 private void instrumentFunctionNode (AstNode node ) {
@@ -1160,6 +1193,41 @@ public void clearFunctionsList() {
11601193 missedFunctions .clear ();
11611194 }
11621195
1196+ public boolean isDOMAPIMethod (String functionName ){
1197+
1198+ String [] DOMAccessMethods = {
1199+ ".getElementById" , ".getElementsByTagName" , ".getElementsByClassName" , ".getElementsByName" ,
1200+ ".createElement" , ".removeChild" , ".appendChild" , ".replaceChild" , ".addEventListener" , ".appendChild" , ".adoptNode" ,
1201+ ".blur" , ".click" , ".createAttribute" , ".createElement" , ".createTextNode" , ".insertBefore" , ".querySelector" , ".querySelectorAll" ,
1202+ ".removeAttribute" , ".removeAttributeNode" , ".removeChild" , ".replaceChild" , ".removeEventListener" , ".setAttribute" , ".setAttributeNode" , ".getAttribute" , ".dblclick" , ".hover" , ".mouseout" , ".mouseover" , ".scroll" , ".select" , ".submit" , ".toggle" , ".trigger" , ".triggerHandler" ,
1203+ ".onclick" , ".ondblclick" , ".onmouseover" , ".onmouseout" , ".onselect" , ".onsubmit" , ".ondrag" , ".ondragover" ,
1204+ ".addClass" , ".removeClass" , ".removeAttr" , ".css" , ".attr" , ".prop" , ".append" , ".appendTo" , ".prepend" , ".prependTo" ,
1205+ ".insertBefore" , ".insertAfter" , ".detach" , ".remove" , ".html"
1206+ };
1207+
1208+ for (String pattern : DOMAccessMethods )
1209+ if (functionName .endsWith (pattern ))
1210+ return true ;
1211+
1212+ if (functionName .equals ("jQuery" ) || functionName .equals ("$" ))
1213+ return true ;
1214+
1215+ return false ;
1216+ }
1217+
1218+ public boolean isDOMElementAttribute (String functionName ){
1219+ String [] DOMElemAtt = { ".innerHTML" , ".attribute" , ".onclick" , ".anchors" , ".documentElement" , ".forms" , ".head" , ".images" , ".links" };
1220+ for (String pattern : DOMElemAtt )
1221+ if (functionName .endsWith (pattern ))
1222+ return true ;
1223+
1224+ if (functionName .contains (".style." ))
1225+ return true ;
1226+
1227+ return false ;
1228+ }
1229+
1230+
11631231 public boolean isEventMethod (String functionName ){
11641232 /**
11651233 jQuery Event Methods
@@ -1199,16 +1267,15 @@ public boolean isEventMethod(String functionName){
11991267 trigger() Triggers all events bound to the selected elements
12001268 triggerHandler() Triggers all functions bound to a specified event for the selected elements
12011269 unload() Deprecated in version 1.8. Attaches an event handler to the unload event
1202-
1203-
1204-
1205- Node.js EventEmitter => emit() : .emit(event, data, ...)
1206-
1207- */
1270+
1271+
1272+ Node.js EventEmitter => emit() : .emit(event, data, ...)
1273+ **/
12081274
12091275 String [] eventMethods = { ".bind" , ".blur" , ".change" , ".click" , ".dblclick" , ".delegate" , ".error" , ".focus" ,
12101276 ".focusin" , ".focusout" , ".hover" , ".keydown" , ".keypress" , ".keyup" , ".live" , ".load" , ".mousedown" , ".mouseenter" , ".mouseleave" , ".mousemove" ,
1211- ".mouseout" , ".mouseover" , ".mouseup" , ".on" , ".one" , ".ready" , ".resize" , ".scroll" , ".select" , ".submit" , ".toggle" , ".trigger" , ".triggerHandler" , ".emit" , ".unload" ,
1277+ ".mouseout" , ".mouseover" , ".mouseup" , ".on" , ".one" , ".ready" , ".resize" , ".scroll" , ".select" , ".submit" , ".toggle" , ".trigger" , ".triggerHandler" , ".unload" ,
1278+ ".emit" ,
12121279
12131280 ".addEventListener" , ".attachEvent" ,
12141281
@@ -1265,21 +1332,28 @@ public boolean isEventMethod(String functionName){
12651332 */
12661333 }
12671334
1335+
12681336 public boolean isAsyncMethod (String functionName ){
12691337 /**
1338+ e.g
12701339 setTimeout(func, delay, [param1, param2, ...])
12711340 setInterval(func, delay[, param1, param2, ...])
1341+ ...
12721342 */
12731343
1274- // TODO: XHR and others from Keheliya's paper
1344+ // Updated based on http://salt.ece.ubc.ca/callback-study/#async-apis
12751345
1276- String [] asyncMethods = { "setImmediate" , "setTimeout" , "setInterval" };
1346+ String [] asyncMethods = { "setImmediate" , "setTimeout" , "setInterval" , "XMLHTTPRequest.open" , "addEventListener" , "onclick" , "process.nextTick" };
1347+ String [] asyncIOPaterns = { "fs." , "net." , "child_process." , "crypto." , "dns." , "domain." , "http." , "https." , "net." , "tls." , "dgram." };
12771348
1278- for (String am : asyncMethods )
1279- if (functionName .equals (am ))
1349+ for (String pattern : asyncMethods )
1350+ if (functionName .endsWith (pattern ))
1351+ return true ;
1352+ for (String pattern : asyncIOPaterns )
1353+ if (functionName .startsWith (pattern ))
12801354 return true ;
1281- return false ;
12821355
1356+ return false ;
12831357 }
12841358
12851359
0 commit comments