| /* |
| * Copyright 2016 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.jjs.impl; |
| |
| import com.google.gwt.core.ext.TreeLogger; |
| import com.google.gwt.core.ext.TreeLogger.Type; |
| import com.google.gwt.dev.jjs.HasSourceInfo; |
| import com.google.gwt.dev.jjs.ast.JDeclaredType; |
| import com.google.gwt.dev.jjs.ast.JField; |
| import com.google.gwt.dev.jjs.ast.JMember; |
| import com.google.gwt.dev.jjs.ast.JMethod; |
| import com.google.gwt.dev.jjs.ast.JType; |
| import com.google.gwt.dev.util.log.AbstractTreeLogger; |
| import com.google.gwt.thirdparty.guava.common.collect.Iterables; |
| import com.google.gwt.thirdparty.guava.common.collect.Multimap; |
| import com.google.gwt.thirdparty.guava.common.collect.Ordering; |
| import com.google.gwt.thirdparty.guava.common.collect.Sets; |
| import com.google.gwt.thirdparty.guava.common.collect.TreeMultimap; |
| |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| /** |
| * Abstract base class for error checking in the full AST. |
| */ |
| public abstract class AbstractRestrictionChecker { |
| private Multimap<String, String> errorsByFilename |
| = TreeMultimap.create(Ordering.natural(), AbstractTreeLogger.LOG_LINE_COMPARATOR); |
| private Multimap<String, String> warningsByFilename |
| = TreeMultimap.create(Ordering.natural(), AbstractTreeLogger.LOG_LINE_COMPARATOR); |
| private Set<String> suggestionMessages = Sets.newLinkedHashSet(); |
| |
| protected static String getDescription(HasSourceInfo hasSourceInfo) { |
| if (hasSourceInfo instanceof JDeclaredType) { |
| return getTypeDescription((JDeclaredType) hasSourceInfo); |
| } else { |
| return getMemberDescription((JMember) hasSourceInfo); |
| } |
| } |
| |
| protected static String getMemberDescription(JMember member) { |
| if (member instanceof JField) { |
| return String.format("'%s'", JjsUtils.getReadableDescription(member)); |
| } |
| JMethod method = (JMethod) member; |
| if ((method.isSyntheticAccidentalOverride() || method.isSynthetic()) |
| // Some synthetic methods are created by JDT, it is not safe to assume |
| // that they will always be overriding and crash the compiler. |
| && !method.getOverriddenMethods().isEmpty()) { |
| JMethod overridenMethod = Iterables.getFirst(method.getOverriddenMethods(), null); |
| return String.format("'%s' (exposed by '%s')", |
| JjsUtils.getReadableDescription(overridenMethod), |
| JjsUtils.getReadableDescription(method.getEnclosingType())); |
| } |
| return String.format("'%s'", JjsUtils.getReadableDescription(method)); |
| } |
| |
| private static String getTypeDescription(JDeclaredType type) { |
| return String.format("'%s'", JjsUtils.getReadableDescription(type)); |
| } |
| |
| protected void logError(String format, JType type) { |
| logError(type, format, JjsUtils.getReadableDescription(type)); |
| } |
| |
| protected void logError(HasSourceInfo hasSourceInfo, String format, Object... args) { |
| errorsByFilename.put(hasSourceInfo.getSourceInfo().getFileName(), |
| String.format("Line %d: ", hasSourceInfo.getSourceInfo().getStartLine()) |
| + String.format(format, args)); |
| } |
| |
| protected void logWarning(HasSourceInfo hasSourceInfo, String format, Object... args) { |
| warningsByFilename.put(hasSourceInfo.getSourceInfo().getFileName(), |
| String.format("Line %d: ", hasSourceInfo.getSourceInfo().getStartLine()) |
| + String.format(format, args)); |
| } |
| |
| protected void logSuggestion(String format, Object... args) { |
| suggestionMessages.add(String.format(format, args)); |
| } |
| |
| protected boolean reportErrorsAndWarnings(TreeLogger logger) { |
| TreeSet<String> filenamesToReport = Sets.newTreeSet( |
| Iterables.concat(errorsByFilename.keySet(), warningsByFilename.keySet())); |
| for (String fileName : filenamesToReport) { |
| boolean hasErrors = !errorsByFilename.get(fileName).isEmpty(); |
| TreeLogger branch = logger.branch( |
| Type.INFO, (hasErrors ? "Errors" : "Warnings") + " in " + fileName); |
| for (String message : errorsByFilename.get(fileName)) { |
| branch.log(Type.ERROR, message); |
| } |
| for (String message :warningsByFilename.get(fileName)) { |
| branch.log(Type.WARN, message); |
| } |
| } |
| for (String message : suggestionMessages) { |
| logger.log(Type.WARN, message); |
| } |
| return !errorsByFilename.isEmpty(); |
| } |
| } |