blob: de325eabd5c640883c30b486fc8e61d1e40ee1e2 [file] [log] [blame]
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.turbine.diag;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.collect.Iterables.getOnlyElement;
import static java.util.Objects.requireNonNull;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.turbine.binder.sym.ClassSymbol;
import com.google.turbine.diag.TurbineError.ErrorKind;
import java.util.Objects;
import javax.tools.Diagnostic;
import org.checkerframework.checker.nullness.qual.Nullable;
/** A compilation error. */
public class TurbineDiagnostic {
private final Diagnostic.Kind severity;
private final ErrorKind kind;
private final ImmutableList<Object> args;
private final @Nullable SourceFile source;
private final int position;
private TurbineDiagnostic(
Diagnostic.Kind severity,
ErrorKind kind,
ImmutableList<Object> args,
@Nullable SourceFile source,
int position) {
this.severity = requireNonNull(severity);
this.kind = requireNonNull(kind);
this.args = requireNonNull(args);
this.source = source;
this.position = position;
}
/** The diagnostic kind. */
public ErrorKind kind() {
return kind;
}
/**
* The diagnostic severity (error, warning, ...). Turbine only produces errors, non-error
* diagnostics are only ever created by annotation processors.
*/
public Diagnostic.Kind severity() {
return severity;
}
boolean isError() {
return severity.equals(Diagnostic.Kind.ERROR);
}
/** The diagnostic message. */
public String diagnostic() {
StringBuilder sb = new StringBuilder(path());
if (line() != -1) {
sb.append(':').append(line());
}
sb.append(": error: ");
sb.append(message()).append(System.lineSeparator());
if (line() != -1 && column() != -1) {
sb.append(CharMatcher.breakingWhitespace().trimTrailingFrom(source.lineMap().line(position)))
.append(System.lineSeparator());
sb.append(Strings.repeat(" ", column() - 1)).append('^');
}
return sb.toString();
}
/** The diagnostic arguments. */
public ImmutableList<Object> args() {
return args;
}
private static TurbineDiagnostic create(
Diagnostic.Kind severity,
ErrorKind kind,
ImmutableList<Object> args,
SourceFile source,
int position) {
switch (kind) {
case SYMBOL_NOT_FOUND:
{
checkArgument(
args.size() == 1 && getOnlyElement(args) instanceof ClassSymbol,
"diagnostic (%s) has invalid argument %s",
kind,
args);
break;
}
default: // fall out
}
return new TurbineDiagnostic(severity, kind, args, source, position);
}
public static TurbineDiagnostic format(Diagnostic.Kind severity, ErrorKind kind, String message) {
return create(severity, kind, ImmutableList.of(message), null, -1);
}
/**
* Formats a diagnostic.
*
* @param source the current source file
* @param kind the error kind
* @param args format args
*/
public static TurbineDiagnostic format(SourceFile source, ErrorKind kind, Object... args) {
return create(Diagnostic.Kind.ERROR, kind, ImmutableList.copyOf(args), source, -1);
}
/**
* Formats a diagnostic.
*
* @param position the diagnostic position
* @param kind the error kind
* @param args format args
*/
public static TurbineDiagnostic format(
Diagnostic.Kind severity, SourceFile source, int position, ErrorKind kind, Object... args) {
return create(severity, kind, ImmutableList.copyOf(args), source, position);
}
@Override
public int hashCode() {
return Objects.hash(kind, source, position);
}
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof TurbineDiagnostic)) {
return false;
}
TurbineDiagnostic that = (TurbineDiagnostic) obj;
return severity.equals(that.severity)
&& kind.equals(that.kind)
&& args.equals(that.args)
&& Objects.equals(source, that.source)
&& position == that.position;
}
public String path() {
return source != null && source.path() != null ? source.path() : "<>";
}
public int line() {
return position != -1 ? source.lineMap().lineNumber(position) : -1;
}
public int column() {
return position != -1 ? source.lineMap().column(position) + 1 : -1;
}
public String message() {
return kind.format(args.toArray());
}
}