1 /*
   2  * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.javac.processing;
  27 
  28 import com.sun.tools.javac.model.JavacElements;
  29 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  30 import com.sun.tools.javac.resources.CompilerProperties.Notes;
  31 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
  32 import com.sun.tools.javac.util.*;
  33 import com.sun.tools.javac.util.DefinedBy.Api;
  34 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
  35 import com.sun.tools.javac.tree.JCTree;
  36 import com.sun.tools.javac.tree.JCTree.*;
  37 import java.util.Set;
  38 import javax.lang.model.element.*;
  39 import javax.tools.JavaFileObject;
  40 import javax.tools.Diagnostic;
  41 import javax.annotation.processing.*;
  42 
  43 /**
  44  * An implementation of the Messager built on top of log.
  45  *
  46  * <p><b>This is NOT part of any supported API.
  47  * If you write code that depends on this, you do so at your own risk.
  48  * This code and its internal interfaces are subject to change or
  49  * deletion without notice.</b>
  50  */
  51 public class JavacMessager implements Messager {
  52     Log log;
  53     JavacProcessingEnvironment processingEnv;
  54     int errorCount = 0;
  55     int warningCount = 0;
  56 
  57     JavacMessager(Context context, JavacProcessingEnvironment processingEnv) {
  58         log = Log.instance(context);
  59         this.processingEnv = processingEnv;
  60     }
  61 
  62     // processingEnv.getElementUtils()
  63 
  64     @DefinedBy(Api.ANNOTATION_PROCESSING)
  65     public void printMessage(Diagnostic.Kind kind, CharSequence msg) {
  66         printMessage(kind, msg, null, null, null);
  67     }
  68 
  69     @DefinedBy(Api.ANNOTATION_PROCESSING)
  70     public void printMessage(Diagnostic.Kind kind, CharSequence msg,
  71                       Element e) {
  72         printMessage(kind, msg, e, null, null);
  73     }
  74 
  75     /**
  76      * Prints a message of the specified kind at the location of the
  77      * annotation mirror of the annotated element.
  78      *
  79      * @param kind the kind of message
  80      * @param msg  the message, or an empty string if none
  81      * @param e    the annotated element
  82      * @param a    the annotation to use as a position hint
  83      */
  84     @DefinedBy(Api.ANNOTATION_PROCESSING)
  85     public void printMessage(Diagnostic.Kind kind, CharSequence msg,
  86                       Element e, AnnotationMirror a) {
  87         printMessage(kind, msg, e, a, null);
  88     }
  89 
  90     /**
  91      * Prints a message of the specified kind at the location of the
  92      * annotation value inside the annotation mirror of the annotated
  93      * element.
  94      *
  95      * @param kind the kind of message
  96      * @param msg  the message, or an empty string if none
  97      * @param e    the annotated element
  98      * @param a    the annotation containing the annotation value
  99      * @param v    the annotation value to use as a position hint
 100      */
 101     @DefinedBy(Api.ANNOTATION_PROCESSING)
 102     public void printMessage(Diagnostic.Kind kind, CharSequence msg,
 103                       Element e, AnnotationMirror a, AnnotationValue v) {
 104         JavaFileObject oldSource = null;
 105         JavaFileObject newSource = null;
 106         JCDiagnostic.DiagnosticPosition pos = null;
 107         JavacElements elemUtils = processingEnv.getElementUtils();
 108         Pair<JCTree, JCCompilationUnit> treeTop = elemUtils.getTreeAndTopLevel(e, a, v);
 109         if (treeTop != null) {
 110             newSource = treeTop.snd.sourcefile;
 111             if (newSource != null) {
 112                 // save the old version and reinstate it later
 113                 oldSource = log.useSource(newSource);
 114                 pos = treeTop.fst.pos();
 115             }
 116         }
 117         try {
 118             switch (kind) {
 119             case ERROR:
 120                 errorCount++;
 121                 log.error(DiagnosticFlag.API, pos, Errors.ProcMessager(msg.toString()));
 122                 break;
 123 
 124             case WARNING:
 125                 warningCount++;
 126                 log.warning(pos, Warnings.ProcMessager(msg.toString()));
 127                 break;
 128 
 129             case MANDATORY_WARNING:
 130                 warningCount++;
 131                 log.mandatoryWarning(pos, Warnings.ProcMessager(msg.toString()));
 132                 break;
 133 
 134             default:
 135                 log.note(pos, Notes.ProcMessager(msg.toString()));
 136                 break;
 137             }
 138         } finally {
 139             // reinstate the saved version, only if it was saved earlier
 140             if (newSource != null)
 141                 log.useSource(oldSource);
 142         }
 143     }
 144 
 145     /**
 146      * Prints an error message.
 147      * Equivalent to {@code printError(null, msg)}.
 148      * @param msg  the message, or an empty string if none
 149      */
 150     public void printError(String msg) {
 151         printMessage(Diagnostic.Kind.ERROR, msg);
 152     }
 153 
 154     /**
 155      * Prints a warning message.
 156      * Equivalent to {@code printWarning(null, msg)}.
 157      * @param msg  the message, or an empty string if none
 158      */
 159     public void printWarning(String msg) {
 160         printMessage(Diagnostic.Kind.WARNING, msg);
 161     }
 162 
 163     /**
 164      * Prints a notice.
 165      * @param msg  the message, or an empty string if none
 166      */
 167     public void printNotice(String msg) {
 168         printMessage(Diagnostic.Kind.NOTE, msg);
 169     }
 170 
 171     public boolean errorRaised() {
 172         return errorCount > 0;
 173     }
 174 
 175     public int errorCount() {
 176         return errorCount;
 177     }
 178 
 179     public int warningCount() {
 180         return warningCount;
 181     }
 182 
 183     public void newRound() {
 184         errorCount = 0;
 185     }
 186 
 187     public String toString() {
 188         return "javac Messager";
 189     }
 190 }