Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add instrumentation for collecting client-side code coverage.
Review at http://gwt-code-reviews.appspot.com/1764803 Review by: cromwellian@google.com git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@11164 8db76d5a-ed1c-0410-87a9-c151d255dfc7
- Loading branch information
isbadawi@google.com
committed
Jul 14, 2012
1 parent
1470301
commit 8549003
Showing
5 changed files
with
651 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
123 changes: 123 additions & 0 deletions
123
dev/core/src/com/google/gwt/dev/js/BaselineCoverageGatherer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
/* | ||
* Copyright 2012 Google Inc. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not | ||
* use this file except in compliance with the License. You may obtain a copy of | ||
* the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations under | ||
* the License. | ||
*/ | ||
package com.google.gwt.dev.js; | ||
|
||
import com.google.gwt.dev.jjs.InternalCompilerException; | ||
import com.google.gwt.dev.jjs.SourceInfo; | ||
import com.google.gwt.dev.jjs.ast.Context; | ||
import com.google.gwt.dev.jjs.ast.JClassLiteral; | ||
import com.google.gwt.dev.jjs.ast.JExpression; | ||
import com.google.gwt.dev.jjs.ast.JMethodCall; | ||
import com.google.gwt.dev.jjs.ast.JProgram; | ||
import com.google.gwt.dev.jjs.ast.JThisRef; | ||
import com.google.gwt.dev.jjs.ast.JVisitor; | ||
import com.google.gwt.dev.jjs.ast.js.JsniMethodBody; | ||
import com.google.gwt.dev.js.ast.JsContext; | ||
import com.google.gwt.dev.js.ast.JsExpression; | ||
import com.google.gwt.thirdparty.guava.common.base.Charsets; | ||
import com.google.gwt.thirdparty.guava.common.collect.HashMultimap; | ||
import com.google.gwt.thirdparty.guava.common.collect.Multimap; | ||
import com.google.gwt.thirdparty.guava.common.collect.Sets; | ||
import com.google.gwt.thirdparty.guava.common.io.Files; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.util.Set; | ||
|
||
/** | ||
* Build up a collection of all instrumentable lines, useful for generating | ||
* coverage reports. | ||
*/ | ||
public class BaselineCoverageGatherer { | ||
public static Multimap<String, Integer> exec(JProgram jProgram) { | ||
if (System.getProperty("gwt.coverage") == null) { | ||
return null; | ||
} | ||
return new BaselineCoverageGatherer(jProgram, getCoveredSourceFiles()).execImpl(); | ||
} | ||
|
||
private static Set<String> getCoveredSourceFiles() { | ||
String filename = System.getProperty("gwt.coverage"); | ||
File instrumentationFile = new File(filename); | ||
try { | ||
return Sets.newHashSet(Files.readLines(instrumentationFile, Charsets.UTF_8)); | ||
} catch (IOException e) { | ||
throw new InternalCompilerException("Could not open " + filename, e); | ||
} | ||
} | ||
|
||
private Multimap<String, Integer> instrumentableLines = HashMultimap.create(); | ||
private Set<String> instrumentedFiles; | ||
private JProgram jProgram; | ||
|
||
private BaselineCoverageGatherer(JProgram jProgram, Set<String> instrumentedFiles) { | ||
this.jProgram = jProgram; | ||
this.instrumentedFiles = instrumentedFiles; | ||
} | ||
|
||
private void cover(SourceInfo info) { | ||
if (instrumentedFiles.contains(info.getFileName())) { | ||
instrumentableLines.put(info.getFileName(), info.getStartLine()); | ||
} | ||
} | ||
|
||
private Multimap<String, Integer> execImpl() { | ||
/** | ||
* Figure out which lines are executable. This is mostly straightforward | ||
* except that we have to avoid some synthetic nodes introduced earlier, | ||
* otherwise e.g. class declarations will be visited. | ||
*/ | ||
new JVisitor() { | ||
@Override public void endVisit(JMethodCall x, Context ctx) { | ||
// this is a bit of a hack. The compiler inserts no-arg super calls, but | ||
// there isn't really a way to detect that they're synthetic, and the | ||
// strategy below of comparing source info with that of the enclosing type | ||
// doesn't work because the enclosing type is set to be that of the superclass. | ||
if (x.getTarget().isSynthetic() || x.toSource().equals("super()")) { | ||
return; | ||
} | ||
endVisit((JExpression) x, ctx); | ||
} | ||
|
||
@Override public void endVisit(JThisRef x, Context ctx) { | ||
if (x.getSourceInfo().equals(x.getClassType().getSourceInfo())) { | ||
return; | ||
} | ||
endVisit((JExpression) x, ctx); | ||
} | ||
|
||
@Override public void endVisit(JClassLiteral x, Context ctx) { | ||
if (x.getSourceInfo().equals(x.getRefType().getSourceInfo())) { | ||
return; | ||
} | ||
endVisit((JExpression) x, ctx); | ||
} | ||
|
||
@Override public void endVisit(JExpression x, Context ctx) { | ||
cover(x.getSourceInfo()); | ||
} | ||
|
||
@Override public void endVisit(JsniMethodBody x, Context ctx) { | ||
new CoverageVisitor(instrumentedFiles) { | ||
@Override public void endVisit(JsExpression x, JsContext ctx) { | ||
cover(x.getSourceInfo()); | ||
} | ||
}.accept(x.getFunc()); | ||
} | ||
}.accept(jProgram); | ||
return instrumentableLines; | ||
} | ||
} |
Oops, something went wrong.