|  | // Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  | package com.android.tools.r8.naming; | 
|  |  | 
|  | import static com.android.tools.r8.position.TextPosition.UNKNOWN_COLUMN; | 
|  |  | 
|  | import com.android.tools.r8.origin.PathOrigin; | 
|  | import com.android.tools.r8.position.TextPosition; | 
|  | import com.android.tools.r8.utils.ExceptionDiagnostic; | 
|  | import com.android.tools.r8.utils.Reporter; | 
|  | import com.android.tools.r8.utils.StringDiagnostic; | 
|  | import com.google.common.collect.ImmutableList; | 
|  | import com.google.common.collect.ImmutableList.Builder; | 
|  | import java.io.BufferedReader; | 
|  | import java.io.IOException; | 
|  | import java.nio.file.Files; | 
|  | import java.nio.file.Path; | 
|  | import java.util.HashSet; | 
|  | import java.util.Set; | 
|  |  | 
|  | public class DictionaryReader implements AutoCloseable { | 
|  |  | 
|  | private final BufferedReader reader; | 
|  | private final Path path; | 
|  |  | 
|  | public DictionaryReader(Path path) throws IOException { | 
|  | this.path = path; | 
|  | this.reader = Files.newBufferedReader(path); | 
|  | } | 
|  |  | 
|  | public String readName(Reporter reporter) throws IOException { | 
|  | assert reader != null; | 
|  |  | 
|  | StringBuilder name = new StringBuilder(); | 
|  | int readCharAsInt; | 
|  | int lineNumber = 1; | 
|  |  | 
|  | while ((readCharAsInt = reader.read()) != -1) { | 
|  | char readChar = (char) readCharAsInt; | 
|  |  | 
|  | if ((name.length() != 0 && Character.isJavaIdentifierPart(readChar)) | 
|  | || (name.length() == 0 && Character.isJavaIdentifierStart(readChar))) { | 
|  | name.append(readChar); | 
|  | } else { | 
|  | boolean isCommentChar = readChar == '#'; | 
|  | boolean isValidEndOfLineInput = readChar == '\n' || readChar == '\r'; | 
|  | if (isCommentChar || isValidEndOfLineInput) { | 
|  | if (isCommentChar) { | 
|  | reader.readLine(); | 
|  | } | 
|  | lineNumber++; | 
|  | } | 
|  | if (isValidEndOfLineInput && name.length() != 0) { | 
|  | return name.toString(); | 
|  | } | 
|  | name = new StringBuilder(); | 
|  | // An illegal character was in the input. We discard the entire line instead of returning as | 
|  | // much as possible, to ensure us not throwing an error in the case of duplicates. | 
|  | if (!isValidEndOfLineInput) { | 
|  | reporter.info( | 
|  | new StringDiagnostic( | 
|  | "Invalid character in dictionary '" + readChar + "'", | 
|  | new PathOrigin(path), | 
|  | new TextPosition(0, lineNumber, UNKNOWN_COLUMN))); | 
|  | reader.readLine(); | 
|  | lineNumber++; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return name.toString(); | 
|  | } | 
|  |  | 
|  | @Override | 
|  | public void close() throws IOException { | 
|  | if (reader != null) { | 
|  | reader.close(); | 
|  | } | 
|  | } | 
|  |  | 
|  | public static ImmutableList<String> readAllNames(Path path, Reporter reporter) { | 
|  | if (path != null) { | 
|  | Set<String> seenNames = new HashSet<>(); | 
|  | Builder<String> namesBuilder = new ImmutableList.Builder<String>(); | 
|  | try (DictionaryReader reader = new DictionaryReader(path);) { | 
|  | String name = reader.readName(reporter); | 
|  | while (!name.isEmpty()) { | 
|  | if (!seenNames.add(name)) { | 
|  | reporter.error( | 
|  | new StringDiagnostic( | 
|  | "Duplicate entry for '" + name + "' in dictionary", new PathOrigin(path))); | 
|  | } | 
|  | namesBuilder.add(name); | 
|  | name = reader.readName(reporter); | 
|  | } | 
|  | } catch (IOException e) { | 
|  | reporter.error(new ExceptionDiagnostic(e, new PathOrigin(path))); | 
|  | } | 
|  | return namesBuilder.build(); | 
|  | } else { | 
|  | return ImmutableList.of(); | 
|  | } | 
|  | } | 
|  | } |