public void visitMappings(EntryVisitor visitor) { boolean pending = false; String sourceName = null; String symbolName = null; FilePosition sourceStartPosition = null; FilePosition startPosition = null; final int lineCount = lines.size(); for (int i = 0; i < lineCount; i++) { ArrayList<Entry> line = lines.get(i); if (line != null) { final int entryCount = line.size(); for (int j = 0; j < entryCount; j++) { Entry entry = line.get(j); if (pending) { FilePosition endPosition = new FilePosition(i, entry.getGeneratedColumn()); visitor.visit(sourceName, symbolName, sourceStartPosition, startPosition, endPosition); pending = false; } if (entry.getSourceFileId() != UNMAPPED) { pending = true; sourceName = sources[entry.getSourceFileId()]; symbolName = (entry.getNameId() != UNMAPPED) ? names[entry.getNameId()] : null; sourceStartPosition = new FilePosition(entry.getSourceLine(), entry.getSourceColumn()); startPosition = new FilePosition(i, entry.getGeneratedColumn()); } } } } }
/** * Decodes the next entry, using the previous encountered values to decode the relative values. * * @param vals An array of integers that represent values in the entry. * @param entryValues The number of entries in the array. * @return The entry object. */ private Entry decodeEntry(int[] vals, int entryValues) { Entry entry; switch (entryValues) { // The first values, if present are in the following order: // 0: the starting column in the current line of the generated file // 1: the id of the original source file // 2: the starting line in the original source // 3: the starting column in the original source // 4: the id of the original symbol name // The values are relative to the last encountered value for that field. // Note: the previously column value for the generated file is reset // to '0' when a new line is encountered. This is done in the 'build' // method. case 1: // An unmapped section of the generated file. entry = new UnmappedEntry(vals[0] + previousCol); // Set the values see for the next entry. previousCol = entry.getGeneratedColumn(); return entry; case 4: // A mapped section of the generated file. entry = new UnnamedEntry( vals[0] + previousCol, vals[1] + previousSrcId, vals[2] + previousSrcLine, vals[3] + previousSrcColumn); // Set the values see for the next entry. previousCol = entry.getGeneratedColumn(); previousSrcId = entry.getSourceFileId(); previousSrcLine = entry.getSourceLine(); previousSrcColumn = entry.getSourceColumn(); return entry; case 5: // A mapped section of the generated file, that has an associated // name. entry = new NamedEntry( vals[0] + previousCol, vals[1] + previousSrcId, vals[2] + previousSrcLine, vals[3] + previousSrcColumn, vals[4] + previousNameId); // Set the values see for the next entry. previousCol = entry.getGeneratedColumn(); previousSrcId = entry.getSourceFileId(); previousSrcLine = entry.getSourceLine(); previousSrcColumn = entry.getSourceColumn(); previousNameId = entry.getNameId(); return entry; default: throw new IllegalStateException("Unexpected number of values for entry:" + entryValues); } }
/** Creates an "OriginalMapping" object for the given entry object. */ private OriginalMapping getOriginalMappingForEntry(Entry entry) { if (entry.getSourceFileId() == UNMAPPED) { return null; } else { // Adjust the line/column here to be start at 1. Builder x = OriginalMapping.newBuilder() .setOriginalFile(sources[entry.getSourceFileId()]) .setLineNumber(entry.getSourceLine() + 1) .setColumnPosition(entry.getSourceColumn() + 1); if (entry.getNameId() != UNMAPPED) { x.setIdentifier(names[entry.getNameId()]); } return x.build(); } }
/** * Reverse the source map; the created mapping will allow us to quickly go from a source file and * line number to a collection of target OriginalMappings. */ private void createReverseMapping() { reverseSourceMapping = new HashMap<String, Map<Integer, Collection<OriginalMapping>>>(); for (int targetLine = 0; targetLine < lines.size(); targetLine++) { ArrayList<Entry> entries = lines.get(targetLine); if (entries != null) { for (Entry entry : entries) { if (entry.getSourceFileId() != UNMAPPED && entry.getSourceLine() != UNMAPPED) { String originalFile = sources[entry.getSourceFileId()]; if (!reverseSourceMapping.containsKey(originalFile)) { reverseSourceMapping.put( originalFile, new HashMap<Integer, Collection<OriginalMapping>>()); } Map<Integer, Collection<OriginalMapping>> lineToCollectionMap = reverseSourceMapping.get(originalFile); int sourceLine = entry.getSourceLine(); if (!lineToCollectionMap.containsKey(sourceLine)) { lineToCollectionMap.put(sourceLine, new ArrayList<OriginalMapping>(1)); } Collection<OriginalMapping> mappings = lineToCollectionMap.get(sourceLine); Builder builder = OriginalMapping.newBuilder() .setLineNumber(targetLine) .setColumnPosition(entry.getGeneratedColumn()); mappings.add(builder.build()); } } } } }
/** Sanity check the entry. */ private void validateEntry(Entry entry) { Preconditions.checkState(line < lineCount); Preconditions.checkState( entry.getSourceFileId() == UNMAPPED || entry.getSourceFileId() < sources.length); Preconditions.checkState(entry.getNameId() == UNMAPPED || entry.getNameId() < names.length); }