AptParsingContext.java

  1. /*
  2.  * Copyright © 2017, Salesforce.com, Inc
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions are met:
  7.  *     * Redistributions of source code must retain the above copyright
  8.  *       notice, this list of conditions and the following disclaimer.
  9.  *     * Redistributions in binary form must reproduce the above copyright
  10.  *       notice, this list of conditions and the following disclaimer in the
  11.  *       documentation and/or other materials provided with the distribution.
  12.  *     * Neither the name of the <organization> nor the
  13.  *       names of its contributors may be used to endorse or promote products
  14.  *       derived from this software without specific prior written permission.
  15.  *
  16.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  17.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19.  * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
  20.  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21.  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25.  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26.  */
  27. package com.salesforce.apt.graph.parser.apt;

  28. import javax.annotation.processing.Filer;
  29. import javax.annotation.processing.Messager;
  30. import javax.lang.model.element.Element;
  31. import javax.lang.model.element.ExecutableElement;
  32. import javax.lang.model.element.TypeElement;
  33. import javax.lang.model.element.VariableElement;
  34. import javax.lang.model.util.Elements;
  35. import javax.lang.model.util.SimpleElementVisitor8;
  36. import javax.lang.model.util.Types;
  37. import javax.tools.Diagnostic.Kind;

  38. import com.salesforce.apt.graph.model.AbstractModel;
  39. import com.salesforce.apt.graph.model.DefinitionModel;
  40. import com.salesforce.apt.graph.model.errors.ErrorMessages;
  41. import com.salesforce.apt.graph.model.errors.ErrorModel;
  42. import com.salesforce.apt.graph.model.storage.apt.AptFilerStore;
  43. import com.salesforce.apt.graph.model.storage.apt.AptResourceLoader;
  44. import com.salesforce.apt.graph.model.storage.apt.ClassFileGsonDefinitionModelStore;
  45. import com.salesforce.apt.graph.parser.ParsingContext;
  46. import com.salesforce.apt.graph.types.impl.AptAssignabilityUtils;

  47. public class AptParsingContext extends ParsingContext {

  48.   private Elements elementUtils;
  49.  
  50.   public AptParsingContext(ErrorMessages messageFormats,
  51.       Filer filer, Elements elementUtils, Types types) {
  52.     super(messageFormats, new AptAssignabilityUtils(types, elementUtils),
  53.         new ClassFileGsonDefinitionModelStore(new AptResourceLoader(elementUtils), new AptFilerStore(filer)));
  54.     this.elementUtils = elementUtils;
  55.   }

  56.   public void addDefinition(DefinitionModel model) {
  57.     super.addDefinition(model);
  58.   }
  59.  
  60.   /**
  61.    * Gives user feedback as info/warnings/errors during compilation (works in m2e with takari-lifecycle).
  62.    *
  63.    * @param messager APT round handler for user messages
  64.    */
  65.   public void outputErrors(Messager messager) {
  66.     Iterable<ErrorModel> errors = checkAndStoreValid();
  67.     for (ErrorModel error : errors) {
  68.       for (AbstractModel model : error.getInvolved()) {
  69.         if (model.getSourceElement().isPresent()) {
  70.           messager.printMessage(Kind.ERROR, error.getMessageOn(model, k -> getMessageFormats().getMessage(k)),
  71.               getCorrespondingElement(elementUtils, model.getSourceElement().get()));
  72.         }
  73.       }
  74.     }
  75.   }
  76.  
  77.  
  78.   public Element getCorrespondingElement(Elements elementUtils, Element element) {
  79.     Current current = new Current(elementUtils);
  80.     return current.visit(element);
  81.   }
  82.  
  83.   private static class Current extends SimpleElementVisitor8<Element, Void> {

  84.     private final Elements elementUtils;
  85.    
  86.     public Current(Elements elementUtils) {
  87.       this.elementUtils = elementUtils;
  88.     }
  89.    
  90.     @Override
  91.     public Element visitVariable(VariableElement e, Void p) {
  92.       return super.visitVariable(e, p);
  93.     }

  94.     @Override
  95.     protected Element defaultAction(Element e, Void p) {
  96.       return super.defaultAction(e, p);
  97.     }

  98.     @Override
  99.     public Element visitType(TypeElement e, Void p) {
  100.       return elementUtils.getTypeElement(e.getQualifiedName());
  101.     }

  102.     @Override
  103.     public Element visitExecutable(ExecutableElement e, Void p) {
  104.       TypeElement type = (TypeElement) visitType((TypeElement)e.getEnclosingElement(), null);
  105.       /*
  106.        * Hacky but works for now.  TODO:  build a proper mechanism to convert an executable element to
  107.        * the current RoundEnv's element representation of the the initial element that was read.
  108.        */
  109.       for (Element element : type.getEnclosedElements()) {
  110.         if (element.toString().equals(e.toString())) {  
  111.           return element;
  112.         }
  113.       }
  114.       return null;
  115.     }

  116.     @Override
  117.     public Element visitUnknown(Element e, Void p) {
  118.       return super.visitUnknown(e, p);
  119.     }
  120.    
  121.   }
  122.  
  123. }