langtools/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java
changeset 41527 e8f487b79e24
parent 40837 d071bcc8d32e
child 41865 3ef02797070d
equal deleted inserted replaced
41526:265017792980 41527:e8f487b79e24
   114 import javax.lang.model.SourceVersion;
   114 import javax.lang.model.SourceVersion;
   115 
   115 
   116 import javax.lang.model.element.ExecutableElement;
   116 import javax.lang.model.element.ExecutableElement;
   117 import javax.lang.model.element.PackageElement;
   117 import javax.lang.model.element.PackageElement;
   118 import javax.lang.model.element.QualifiedNameable;
   118 import javax.lang.model.element.QualifiedNameable;
       
   119 import javax.lang.model.element.TypeParameterElement;
   119 import javax.lang.model.element.VariableElement;
   120 import javax.lang.model.element.VariableElement;
   120 import javax.lang.model.type.ArrayType;
   121 import javax.lang.model.type.ArrayType;
   121 import javax.lang.model.type.ExecutableType;
   122 import javax.lang.model.type.ExecutableType;
   122 import javax.lang.model.type.TypeKind;
   123 import javax.lang.model.type.TypeKind;
   123 import javax.lang.model.util.ElementFilter;
   124 import javax.lang.model.util.ElementFilter;
   130 import javax.tools.ToolProvider;
   131 import javax.tools.ToolProvider;
   131 
   132 
   132 import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
   133 import static jdk.jshell.Util.REPL_DOESNOTMATTER_CLASS_NAME;
   133 import static java.util.stream.Collectors.joining;
   134 import static java.util.stream.Collectors.joining;
   134 import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE;
   135 import static jdk.jshell.SourceCodeAnalysis.Completeness.DEFINITELY_INCOMPLETE;
       
   136 import static jdk.jshell.TreeDissector.printType;
   135 
   137 
   136 /**
   138 /**
   137  * The concrete implementation of SourceCodeAnalysis.
   139  * The concrete implementation of SourceCodeAnalysis.
   138  * @author Robert Field
   140  * @author Robert Field
   139  */
   141  */
  1183             }
  1185             }
  1184         } catch (IOException ex) {
  1186         } catch (IOException ex) {
  1185             proc.debug(ex, "SourceCodeAnalysisImpl.element2String(..., " + el + ")");
  1187             proc.debug(ex, "SourceCodeAnalysisImpl.element2String(..., " + el + ")");
  1186         }
  1188         }
  1187 
  1189 
  1188         return Util.expunge(elementHeader(el));
  1190         return Util.expunge(elementHeader(sourceCache.originalTask, el, !hasSyntheticParameterNames(el)));
  1189     }
  1191     }
  1190 
  1192 
  1191     private boolean hasSyntheticParameterNames(Element el) {
  1193     private boolean hasSyntheticParameterNames(Element el) {
  1192         if (el.getKind() != ElementKind.CONSTRUCTOR && el.getKind() != ElementKind.METHOD)
  1194         if (el.getKind() != ElementKind.CONSTRUCTOR && el.getKind() != ElementKind.METHOD)
  1193             return false;
  1195             return false;
  1246 
  1248 
  1247             if (cache == null) {
  1249             if (cache == null) {
  1248                 topLevelName2Signature2Method.put(binaryName, cache = createMethodCache(binaryName));
  1250                 topLevelName2Signature2Method.put(binaryName, cache = createMethodCache(binaryName));
  1249             }
  1251             }
  1250 
  1252 
  1251             String handle = elementHeader(method, false);
  1253             String handle = elementHeader(originalTask, method, false);
  1252 
  1254 
  1253             return cache.getOrDefault(handle, method);
  1255             return cache.getOrDefault(handle, method);
  1254         }
  1256         }
  1255 
  1257 
  1256         private TypeElement topLevelType(Element el) {
  1258         private TypeElement topLevelType(Element el) {
  1274                 @Override
  1276                 @Override
  1275                 public Void visitMethod(MethodTree node, Void p) {
  1277                 public Void visitMethod(MethodTree node, Void p) {
  1276                     Element currentMethod = trees.getElement(getCurrentPath());
  1278                     Element currentMethod = trees.getElement(getCurrentPath());
  1277 
  1279 
  1278                     if (currentMethod != null) {
  1280                     if (currentMethod != null) {
  1279                         signature2Method.put(elementHeader(currentMethod, false), currentMethod);
  1281                         signature2Method.put(elementHeader(originalTask, currentMethod, false), currentMethod);
  1280                     }
  1282                     }
  1281 
  1283 
  1282                     return null;
  1284                     return null;
  1283                 }
  1285                 }
  1284             }.scan(source.snd, null);
  1286             }.scan(source.snd, null);
  1329         if (Files.isReadable(srcZip))
  1331         if (Files.isReadable(srcZip))
  1330             result.add(srcZip);
  1332             result.add(srcZip);
  1331         return availableSources = result;
  1333         return availableSources = result;
  1332     }
  1334     }
  1333 
  1335 
  1334     private String elementHeader(Element el) {
  1336     private String elementHeader(AnalyzeTask at, Element el) {
  1335         return elementHeader(el, true);
  1337         return elementHeader(at, el, true);
  1336     }
  1338     }
  1337 
  1339 
  1338     private String elementHeader(Element el, boolean includeParameterNames) {
  1340     private String elementHeader(AnalyzeTask at, Element el, boolean includeParameterNames) {
  1339         switch (el.getKind()) {
  1341         switch (el.getKind()) {
  1340             case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE:
  1342             case ANNOTATION_TYPE: case CLASS: case ENUM: case INTERFACE: {
  1341                 return ((TypeElement) el).getQualifiedName().toString();
  1343                 TypeElement type = (TypeElement)el;
       
  1344                 String fullname = type.getQualifiedName().toString();
       
  1345                 Element pkg = at.getElements().getPackageOf(el);
       
  1346                 String name = pkg == null ? fullname :
       
  1347                         proc.maps.fullClassNameAndPackageToClass(fullname, ((PackageElement)pkg).getQualifiedName().toString());
       
  1348 
       
  1349                 return name + typeParametersOpt(at, type.getTypeParameters());
       
  1350             }
       
  1351             case TYPE_PARAMETER: {
       
  1352                 TypeParameterElement tp = (TypeParameterElement)el;
       
  1353                 String name = tp.getSimpleName().toString();
       
  1354 
       
  1355                 List<? extends TypeMirror> bounds = tp.getBounds();
       
  1356                 boolean boundIsObject = bounds.isEmpty() ||
       
  1357                         bounds.size() == 1 && at.getTypes().isSameType(bounds.get(0), Symtab.instance(at.getContext()).objectType);
       
  1358 
       
  1359                 return boundIsObject
       
  1360                         ? name
       
  1361                         : name + " extends " + bounds.stream()
       
  1362                                 .map(bound -> printType(at, proc, bound))
       
  1363                                 .collect(joining(" & "));
       
  1364             }
  1342             case FIELD:
  1365             case FIELD:
  1343                 return elementHeader(el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType();
  1366                 return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName() + ":" + el.asType();
  1344             case ENUM_CONSTANT:
  1367             case ENUM_CONSTANT:
  1345                 return elementHeader(el.getEnclosingElement()) + "." + el.getSimpleName();
  1368                 return elementHeader(at, el.getEnclosingElement()) + "." + el.getSimpleName();
  1346             case EXCEPTION_PARAMETER: case LOCAL_VARIABLE: case PARAMETER: case RESOURCE_VARIABLE:
  1369             case EXCEPTION_PARAMETER: case LOCAL_VARIABLE: case PARAMETER: case RESOURCE_VARIABLE:
  1347                 return el.getSimpleName() + ":" + el.asType();
  1370                 return el.getSimpleName() + ":" + el.asType();
  1348             case CONSTRUCTOR: case METHOD:
  1371             case CONSTRUCTOR: case METHOD: {
  1349                 StringBuilder header = new StringBuilder();
  1372                 StringBuilder header = new StringBuilder();
  1350                 header.append(elementHeader(el.getEnclosingElement()));
  1373 
  1351                 if (el.getKind() == ElementKind.METHOD) {
  1374                 boolean isMethod = el.getKind() == ElementKind.METHOD;
  1352                     header.append(".");
  1375                 ExecutableElement method = (ExecutableElement) el;
  1353                     header.append(el.getSimpleName());
  1376 
  1354                 }
  1377                 if (isMethod) {
       
  1378                     // return type
       
  1379                     header.append(printType(at, proc, method.getReturnType())).append(" ");
       
  1380                 } else {
       
  1381                     // type parameters for the constructor
       
  1382                     String typeParameters = typeParametersOpt(at, method.getTypeParameters());
       
  1383                     if (!typeParameters.isEmpty()) {
       
  1384                         header.append(typeParameters).append(" ");
       
  1385                     }
       
  1386                 }
       
  1387 
       
  1388                 // receiver type
       
  1389                 String clazz = elementHeader(at, el.getEnclosingElement());
       
  1390                 header.append(clazz);
       
  1391 
       
  1392                 if (isMethod) {
       
  1393                     //method name with type parameters
       
  1394                     (clazz.isEmpty() ? header : header.append("."))
       
  1395                             .append(typeParametersOpt(at, method.getTypeParameters()))
       
  1396                             .append(el.getSimpleName());
       
  1397                 }
       
  1398 
       
  1399                 // arguments
  1355                 header.append("(");
  1400                 header.append("(");
  1356                 String sep = "";
  1401                 String sep = "";
  1357                 ExecutableElement method = (ExecutableElement) el;
       
  1358                 for (Iterator<? extends VariableElement> i = method.getParameters().iterator(); i.hasNext();) {
  1402                 for (Iterator<? extends VariableElement> i = method.getParameters().iterator(); i.hasNext();) {
  1359                     VariableElement p = i.next();
  1403                     VariableElement p = i.next();
  1360                     header.append(sep);
  1404                     header.append(sep);
  1361                     if (!i.hasNext() && method.isVarArgs()) {
  1405                     if (!i.hasNext() && method.isVarArgs()) {
  1362                         header.append(unwrapArrayType(p.asType()));
  1406                         header.append(printType(at, proc, unwrapArrayType(p.asType()))).append("...");
  1363                         header.append("...");
       
  1364 
       
  1365                     } else {
  1407                     } else {
  1366                         header.append(p.asType());
  1408                         header.append(printType(at, proc, p.asType()));
  1367                     }
  1409                     }
  1368                     if (includeParameterNames) {
  1410                     if (includeParameterNames) {
  1369                         header.append(" ");
  1411                         header.append(" ");
  1370                         header.append(p.getSimpleName());
  1412                         header.append(p.getSimpleName());
  1371                     }
  1413                     }
  1372                     sep = ", ";
  1414                     sep = ", ";
  1373                 }
  1415                 }
  1374                 header.append(")");
  1416                 header.append(")");
       
  1417 
       
  1418                 // throws
       
  1419                 List<? extends TypeMirror> thrownTypes = method.getThrownTypes();
       
  1420                 if (!thrownTypes.isEmpty()) {
       
  1421                     header.append(" throws ")
       
  1422                             .append(thrownTypes.stream()
       
  1423                                     .map(type -> printType(at, proc, type))
       
  1424                                     .collect(joining(", ")));
       
  1425                 }
  1375                 return header.toString();
  1426                 return header.toString();
  1376            default:
  1427             }
       
  1428             default:
  1377                 return el.toString();
  1429                 return el.toString();
  1378         }
  1430         }
  1379     }
  1431     }
  1380     private TypeMirror unwrapArrayType(TypeMirror arrayType) {
  1432     private TypeMirror unwrapArrayType(TypeMirror arrayType) {
  1381         if (arrayType.getKind() == TypeKind.ARRAY) {
  1433         if (arrayType.getKind() == TypeKind.ARRAY) {
  1382             return ((ArrayType)arrayType).getComponentType();
  1434             return ((ArrayType)arrayType).getComponentType();
  1383         }
  1435         }
  1384         return arrayType;
  1436         return arrayType;
       
  1437     }
       
  1438     private String typeParametersOpt(AnalyzeTask at, List<? extends TypeParameterElement> typeParameters) {
       
  1439         return typeParameters.isEmpty() ? ""
       
  1440                 : typeParameters.stream()
       
  1441                         .map(tp -> elementHeader(at, tp))
       
  1442                         .collect(joining(", ", "<", ">"));
  1385     }
  1443     }
  1386 
  1444 
  1387     @Override
  1445     @Override
  1388     public String analyzeType(String code, int cursor) {
  1446     public String analyzeType(String code, int cursor) {
  1389         code = code.substring(0, cursor);
  1447         code = code.substring(0, cursor);