All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sourcegraph.semanticdb_javac.SemanticdbTrees Maven / Gradle / Ivy

There is a newer version: 0.10.3
Show newest version
package com.sourcegraph.semanticdb_javac;

import com.sun.source.tree.Tree;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.tree.JCTree;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static com.sourcegraph.semanticdb_javac.SemanticdbBuilders.*;
import static com.sourcegraph.semanticdb_javac.SemanticdbTypeVisitor.ARRAY_SYMBOL;

public class SemanticdbTrees {
  public SemanticdbTrees(
      GlobalSymbolsCache globals, LocalSymbolsCache locals, String semanticdbUri) {
    this.globals = globals;
    this.locals = locals;
    this.semanticdbUri = semanticdbUri;
  }

  private final GlobalSymbolsCache globals;
  private final LocalSymbolsCache locals;
  private final String semanticdbUri;

  public List annotations(JCTree node) {
    if (!(node instanceof JCTree.JCClassDecl)
        && !(node instanceof JCTree.JCVariableDecl)
        && !(node instanceof JCTree.JCMethodDecl)) return null;

    List annotations = new ArrayList<>();

    JCTree.JCModifiers mods;
    if (node instanceof JCTree.JCClassDecl) {
      mods = ((JCTree.JCClassDecl) node).getModifiers();
    } else if (node instanceof JCTree.JCMethodDecl) {
      mods = ((JCTree.JCMethodDecl) node).getModifiers();
    } else {
      mods = ((JCTree.JCVariableDecl) node).getModifiers();
    }

    for (JCTree.JCAnnotation annotation : mods.getAnnotations()) {
      annotations.add(annotationBuilder(annotation));
    }

    return annotations;
  }

  private Semanticdb.AnnotationTree annotationBuilder(JCTree.JCAnnotation annotation) {
    ArrayList params = new ArrayList<>(annotation.args.size());

    for (JCTree.JCExpression param : annotation.args) {
      // anecdotally not always JCAssign in some situations when a compilation unit can't resolve
      // symbols fully
      if (param instanceof JCTree.JCAssign) {
        JCTree.JCAssign assign = (JCTree.JCAssign) param;
        JCTree.JCExpression assignValue = assign.rhs;

        String symbol = globals.semanticdbSymbol(((JCTree.JCIdent) assign.lhs).sym, locals);
        params.add(tree(assignTree(tree(idTree(symbol)), annotationParameter(assignValue))));
      } else {
        params.add(annotationParameter(param));
      }
    }

    Semanticdb.Type type =
        new SemanticdbTypeVisitor(globals, locals).semanticdbType(annotation.type);
    return annotationTree(type, params);
  }

  private Semanticdb.Tree annotationParameter(JCTree.JCExpression expr) {
    if (expr instanceof JCTree.JCFieldAccess) {
      JCTree.JCFieldAccess rhs = (JCTree.JCFieldAccess) expr;

      return tree(
          selectTree(
              tree(idTree(globals.semanticdbSymbol(rhs.sym.owner, locals))),
              idTree(globals.semanticdbSymbol(rhs.sym, locals))));
    } else if (expr instanceof JCTree.JCNewArray) {
      JCTree.JCNewArray rhs = (JCTree.JCNewArray) expr;
      return tree(
          applyTree(
              tree(idTree(ARRAY_SYMBOL)),
              rhs.elems.stream().map(this::annotationParameter).collect(Collectors.toList())));
    } else if (expr instanceof JCTree.JCLiteral) {
      // Literals can either be a primitive or String
      JCTree.JCLiteral rhs = (JCTree.JCLiteral) expr;

      if (rhs.type instanceof Type.JCPrimitiveType) {
        Type.JCPrimitiveType type = (Type.JCPrimitiveType) rhs.type;
        switch (type.getKind()) {
          case BOOLEAN:
            return tree(literalTree(booleanConst(((Integer) rhs.value) == 1)));
          case BYTE:
            return tree(literalTree(byteConst((Byte) rhs.value)));
          case SHORT:
            return tree(literalTree(shortConst((Short) rhs.value)));
          case INT:
            return tree(literalTree(intConst((Integer) rhs.value)));
          case LONG:
            return tree(literalTree(longConst((Long) rhs.value)));
          case CHAR:
            return tree(literalTree(charConst((Character.forDigit((Integer) rhs.value, 10)))));
          case FLOAT:
            return tree(literalTree(floatConst((Float) rhs.value)));
          case DOUBLE:
            return tree(literalTree(doubleConst((Double) rhs.value)));
        }
      } else if (rhs.type instanceof Type.ClassType) {
        if (rhs.value instanceof String) {
          return tree(literalTree(stringConst((String) rhs.value)));
        } else {
          throw new IllegalStateException(
              semanticdbUri
                  + ": annotation parameter rhs was of unexpected class type "
                  + rhs.value.getClass()
                  + "\n"
                  + rhs.value);
        }
      } else if (rhs.type instanceof Type.UnknownType) {
        return tree(literalTree(stringConst("UNRESOLVED")));
      } else {
        throw new IllegalStateException(
            semanticdbUri
                + ": annotation parameter rhs was of unexpected type "
                + rhs.type.getClass()
                + "\n"
                + rhs.type
                + " "
                + rhs);
      }
    } else if (expr instanceof JCTree.JCAnnotation) {
      return tree(annotationBuilder((JCTree.JCAnnotation) expr));
    } else if (expr instanceof JCTree.JCIdent) {
      return tree(idTree(globals.semanticdbSymbol(((JCTree.JCIdent) expr).sym, locals)));
    } else if (expr instanceof JCTree.JCBinary) {
      JCTree.JCBinary binExpr = (JCTree.JCBinary) expr;
      return tree(
          binopTree(
              annotationParameter(binExpr.lhs),
              semanticdbBinaryOperator(expr.getKind()),
              annotationParameter(binExpr.rhs)));
    }

    throw new IllegalArgumentException(
        semanticdbUri
            + ": annotation parameter rhs was of unexpected tree node type "
            + expr.getClass()
            + "\n"
            + expr);
  }

  private Semanticdb.BinaryOperator semanticdbBinaryOperator(Tree.Kind kind) {
    switch (kind) {
      case PLUS:
        return Semanticdb.BinaryOperator.PLUS;
      case MINUS:
        return Semanticdb.BinaryOperator.MINUS;
      case MULTIPLY:
        return Semanticdb.BinaryOperator.MULTIPLY;
      case DIVIDE:
        return Semanticdb.BinaryOperator.DIVIDE;
      case REMAINDER:
        return Semanticdb.BinaryOperator.REMAINDER;
      case LESS_THAN:
        return Semanticdb.BinaryOperator.LESS_THAN;
      case GREATER_THAN:
        return Semanticdb.BinaryOperator.GREATER_THAN;
      case LEFT_SHIFT:
        return Semanticdb.BinaryOperator.SHIFT_LEFT;
      case RIGHT_SHIFT:
        return Semanticdb.BinaryOperator.SHIFT_RIGHT;
      case UNSIGNED_RIGHT_SHIFT:
        return Semanticdb.BinaryOperator.SHIFT_RIGHT_UNSIGNED;
      case EQUAL_TO:
        return Semanticdb.BinaryOperator.EQUAL_TO;
      case NOT_EQUAL_TO:
        return Semanticdb.BinaryOperator.NOT_EQUAL_TO;
      case LESS_THAN_EQUAL:
        return Semanticdb.BinaryOperator.LESS_THAN_EQUAL;
      case GREATER_THAN_EQUAL:
        return Semanticdb.BinaryOperator.GREATER_THAN_EQUAL;
      case CONDITIONAL_AND:
        return Semanticdb.BinaryOperator.CONDITIONAL_AND;
      case CONDITIONAL_OR:
        return Semanticdb.BinaryOperator.CONDITIONAL_OR;
      case AND:
        return Semanticdb.BinaryOperator.AND;
      case OR:
        return Semanticdb.BinaryOperator.OR;
      case XOR:
        return Semanticdb.BinaryOperator.XOR;
      default:
        throw new IllegalStateException(
            semanticdbUri + ": unexpected binary expression operator kind " + kind);
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy