1 /* |
1 /* |
2 * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
42 import com.sun.source.tree.MethodTree; |
42 import com.sun.source.tree.MethodTree; |
43 import com.sun.source.tree.ModifiersTree; |
43 import com.sun.source.tree.ModifiersTree; |
44 import com.sun.source.tree.NewClassTree; |
44 import com.sun.source.tree.NewClassTree; |
45 import com.sun.source.tree.Tree; |
45 import com.sun.source.tree.Tree; |
46 import com.sun.source.tree.VariableTree; |
46 import com.sun.source.tree.VariableTree; |
47 import com.sun.source.util.TreeScanner; |
|
48 import com.sun.tools.javac.tree.JCTree; |
47 import com.sun.tools.javac.tree.JCTree; |
49 import com.sun.tools.javac.tree.Pretty; |
48 import com.sun.tools.javac.tree.Pretty; |
50 import java.io.IOException; |
49 import java.io.IOException; |
51 import java.io.StringWriter; |
50 import java.io.StringWriter; |
52 import java.io.Writer; |
51 import java.io.Writer; |
96 * @author Robert Field |
95 * @author Robert Field |
97 */ |
96 */ |
98 class Eval { |
97 class Eval { |
99 |
98 |
100 private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\p{javaWhitespace}+(?<static>static\\p{javaWhitespace}+)?(?<fullname>[\\p{L}\\p{N}_\\$\\.]+\\.(?<name>[\\p{L}\\p{N}_\\$]+|\\*))"); |
99 private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\p{javaWhitespace}+(?<static>static\\p{javaWhitespace}+)?(?<fullname>[\\p{L}\\p{N}_\\$\\.]+\\.(?<name>[\\p{L}\\p{N}_\\$]+|\\*))"); |
|
100 private static final Pattern DEFAULT_PREFIX = Pattern.compile("\\p{javaWhitespace}*(default)\\p{javaWhitespace}+"); |
101 |
101 |
102 // for uses that should not change state -- non-evaluations |
102 // for uses that should not change state -- non-evaluations |
103 private boolean preserveState = false; |
103 private boolean preserveState = false; |
104 |
104 |
105 private int varNumber = 0; |
105 private int varNumber = 0; |
199 if (units.isEmpty()) { |
199 if (units.isEmpty()) { |
200 return compileFailResult(pt, userSource, Kind.ERRONEOUS); |
200 return compileFailResult(pt, userSource, Kind.ERRONEOUS); |
201 } |
201 } |
202 Tree unitTree = units.get(0); |
202 Tree unitTree = units.get(0); |
203 if (pt.getDiagnostics().hasOtherThanNotStatementErrors()) { |
203 if (pt.getDiagnostics().hasOtherThanNotStatementErrors()) { |
204 return compileFailResult(pt, userSource, kindOfTree(unitTree)); |
204 Matcher matcher = DEFAULT_PREFIX.matcher(compileSource); |
|
205 DiagList dlist = matcher.lookingAt() |
|
206 ? new DiagList(new ModifierDiagnostic(true, |
|
207 state.messageFormat("jshell.diag.modifier.single.fatal", "'default'"), |
|
208 matcher.start(1), matcher.end(1))) |
|
209 : pt.getDiagnostics(); |
|
210 return compileFailResult(dlist, userSource, kindOfTree(unitTree)); |
205 } |
211 } |
206 |
212 |
207 // Erase illegal/ignored modifiers |
213 // Erase illegal/ignored modifiers |
208 String compileSourceInt = new MaskCommentsAndModifiers(compileSource, true).cleared(); |
214 String compileSourceInt = new MaskCommentsAndModifiers(compileSource, true).cleared(); |
209 |
215 |
613 } |
619 } |
614 while (name == null || state.keyMap.doesVariableNameExist(name)) { |
620 while (name == null || state.keyMap.doesVariableNameExist(name)) { |
615 name = "$" + ++varNumber; |
621 name = "$" + ++varNumber; |
616 } |
622 } |
617 } |
623 } |
618 TreeDissector dis = TreeDissector.createByFirstClass(pt); |
|
619 ExpressionInfo varEI = |
624 ExpressionInfo varEI = |
620 ExpressionToTypeInfo.localVariableTypeForInitializer(compileSource, state, true); |
625 ExpressionToTypeInfo.localVariableTypeForInitializer(compileSource, state, true); |
621 String declareTypeName; |
626 String declareTypeName; |
622 String fullTypeName; |
627 String fullTypeName; |
623 String displayTypeName; |
628 String displayTypeName; |
625 if (varEI != null) { |
630 if (varEI != null) { |
626 declareTypeName = varEI.declareTypeName; |
631 declareTypeName = varEI.declareTypeName; |
627 fullTypeName = varEI.fullTypeName; |
632 fullTypeName = varEI.fullTypeName; |
628 displayTypeName = varEI.displayTypeName; |
633 displayTypeName = varEI.displayTypeName; |
629 |
634 |
|
635 TreeDissector dis = TreeDissector.createByFirstClass(pt); |
630 Pair<Wrap, Wrap> anonymous2Member = |
636 Pair<Wrap, Wrap> anonymous2Member = |
631 anonymous2Member(varEI, compileSource, new Range(0, compileSource.length()), dis, expr.getExpression()); |
637 anonymous2Member(varEI, compileSource, new Range(0, compileSource.length()), dis, expr.getExpression()); |
632 guts = Wrap.tempVarWrap(anonymous2Member.second.wrapped(), declareTypeName, name, anonymous2Member.first); |
638 guts = Wrap.tempVarWrap(anonymous2Member.second.wrapped(), declareTypeName, name, anonymous2Member.first); |
633 anonymousClasses = varEI.anonymousClasses.stream().map(ad -> ad.declareTypeName).collect(Collectors.toSet()); |
639 anonymousClasses = varEI.anonymousClasses.stream().map(ad -> ad.declareTypeName).collect(Collectors.toSet()); |
634 } else { |
640 } else { |
671 |
677 |
672 ClassTree klassTree = (ClassTree) unitTree; |
678 ClassTree klassTree = (ClassTree) unitTree; |
673 String name = klassTree.getSimpleName().toString(); |
679 String name = klassTree.getSimpleName().toString(); |
674 DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false); |
680 DiagList modDiag = modifierDiagnostics(klassTree.getModifiers(), dis, false); |
675 TypeDeclKey key = state.keyMap.keyForClass(name); |
681 TypeDeclKey key = state.keyMap.keyForClass(name); |
676 // Corralling mutates. Must be last use of pt, unitTree, klassTree |
682 // Corralling |
677 Wrap corralled = new Corraller(key.index(), pt.getContext()).corralType(klassTree); |
683 Wrap corralled = new Corraller(dis, key.index(), compileSource).corralType(klassTree); |
678 |
684 |
679 Wrap guts = Wrap.classMemberWrap(compileSource); |
685 Wrap guts = Wrap.classMemberWrap(compileSource); |
680 Snippet snip = new TypeDeclSnippet(key, userSource, guts, |
686 Snippet snip = new TypeDeclSnippet(key, userSource, guts, |
681 name, snippetKind, |
687 name, snippetKind, |
682 corralled, tds.declareReferences(), tds.bodyReferences(), modDiag); |
688 corralled, tds.declareReferences(), tds.bodyReferences(), modDiag); |
743 .map(param -> dis.treeToRange(param.getType()).part(compileSource)) |
749 .map(param -> dis.treeToRange(param.getType()).part(compileSource)) |
744 .collect(Collectors.joining(",")); |
750 .collect(Collectors.joining(",")); |
745 Tree returnType = mt.getReturnType(); |
751 Tree returnType = mt.getReturnType(); |
746 DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true); |
752 DiagList modDiag = modifierDiagnostics(mt.getModifiers(), dis, true); |
747 MethodKey key = state.keyMap.keyForMethod(name, parameterTypes); |
753 MethodKey key = state.keyMap.keyForMethod(name, parameterTypes); |
748 // Corralling mutates. Must be last use of pt, unitTree, mt |
754 // Corralling |
749 Wrap corralled = new Corraller(key.index(), pt.getContext()).corralMethod(mt); |
755 Wrap corralled = new Corraller(dis, key.index(), compileSource).corralMethod(mt); |
750 |
756 |
751 if (modDiag.hasErrors()) { |
757 if (modDiag.hasErrors()) { |
752 return compileFailResult(modDiag, userSource, Kind.METHOD); |
758 return compileFailResult(modDiag, userSource, Kind.METHOD); |
753 } |
759 } |
754 Wrap guts = Wrap.classMemberWrap(compileSource); |
760 Wrap guts = Wrap.classMemberWrap(compileSource); |
965 ins.stream().forEach(u -> u.setWrap(ins, ins)); |
971 ins.stream().forEach(u -> u.setWrap(ins, ins)); |
966 state.taskFactory.analyze(outerWrapSet(ins), at -> { |
972 state.taskFactory.analyze(outerWrapSet(ins), at -> { |
967 ins.stream().forEach(u -> u.setDiagnostics(at)); |
973 ins.stream().forEach(u -> u.setDiagnostics(at)); |
968 |
974 |
969 // corral any Snippets that need it |
975 // corral any Snippets that need it |
970 if (ins.stream().anyMatch(u -> u.corralIfNeeded(ins))) { |
976 if (ins.stream().filter(u -> u.corralIfNeeded(ins)).count() > 0) { |
971 // if any were corralled, re-analyze everything |
977 // if any were corralled, re-analyze everything |
972 state.taskFactory.analyze(outerWrapSet(ins), cat -> { |
978 state.taskFactory.analyze(outerWrapSet(ins), cat -> { |
973 ins.stream().forEach(u -> u.setCorralledDiagnostics(cat)); |
979 ins.stream().forEach(u -> u.setCorralledDiagnostics(cat)); |
974 ins.stream().forEach(u -> u.setStatus(cat)); |
980 ins.stream().forEach(u -> u.setStatus(cat)); |
975 return null; |
981 return null; |
1152 String.join(" ", objectMethods)); |
1158 String.join(" ", objectMethods)); |
1153 } |
1159 } |
1154 }; |
1160 }; |
1155 } |
1161 } |
1156 |
1162 |
1157 private DiagList modifierDiagnostics(ModifiersTree modtree, |
1163 private class ModifierDiagnostic extends Diag { |
1158 final TreeDissector dis, boolean isAbstractProhibited) { |
|
1159 |
|
1160 class ModifierDiagnostic extends Diag { |
|
1161 |
1164 |
1162 final boolean fatal; |
1165 final boolean fatal; |
1163 final String message; |
1166 final String message; |
1164 long start; |
1167 final long start; |
1165 long end; |
1168 final long end; |
1166 |
1169 |
1167 ModifierDiagnostic(List<Modifier> list, boolean fatal) { |
1170 ModifierDiagnostic(boolean fatal, |
|
1171 final String message, |
|
1172 long start, |
|
1173 long end) { |
1168 this.fatal = fatal; |
1174 this.fatal = fatal; |
1169 StringBuilder sb = new StringBuilder(); |
1175 this.message = message; |
1170 for (Modifier mod : list) { |
1176 this.start = start; |
1171 sb.append("'"); |
1177 this.end = end; |
1172 sb.append(mod.toString()); |
|
1173 sb.append("' "); |
|
1174 } |
|
1175 String key = (list.size() > 1) |
|
1176 ? fatal |
|
1177 ? "jshell.diag.modifier.plural.fatal" |
|
1178 : "jshell.diag.modifier.plural.ignore" |
|
1179 : fatal |
|
1180 ? "jshell.diag.modifier.single.fatal" |
|
1181 : "jshell.diag.modifier.single.ignore"; |
|
1182 this.message = state.messageFormat(key, sb.toString()); |
|
1183 start = dis.getStartPosition(modtree); |
|
1184 end = dis.getEndPosition(modtree); |
|
1185 } |
1178 } |
1186 |
1179 |
1187 @Override |
1180 @Override |
1188 public boolean isError() { |
1181 public boolean isError() { |
1189 return fatal; |
1182 return fatal; |
1213 |
1206 |
1214 @Override |
1207 @Override |
1215 public String getMessage(Locale locale) { |
1208 public String getMessage(Locale locale) { |
1216 return message; |
1209 return message; |
1217 } |
1210 } |
1218 } |
1211 } |
|
1212 |
|
1213 private DiagList modifierDiagnostics(ModifiersTree modtree, |
|
1214 final TreeDissector dis, boolean isAbstractProhibited) { |
1219 |
1215 |
1220 List<Modifier> list = new ArrayList<>(); |
1216 List<Modifier> list = new ArrayList<>(); |
1221 boolean fatal = false; |
1217 boolean fatal = false; |
1222 for (Modifier mod : modtree.getFlags()) { |
1218 for (Modifier mod : modtree.getFlags()) { |
1223 switch (mod) { |
1219 switch (mod) { |
1241 case FINAL: |
1237 case FINAL: |
1242 list.add(mod); |
1238 list.add(mod); |
1243 break; |
1239 break; |
1244 } |
1240 } |
1245 } |
1241 } |
1246 return list.isEmpty() |
1242 if (list.isEmpty()) { |
1247 ? new DiagList() |
1243 return new DiagList(); |
1248 : new DiagList(new ModifierDiagnostic(list, fatal)); |
1244 } else { |
|
1245 StringBuilder sb = new StringBuilder(); |
|
1246 for (Modifier mod : list) { |
|
1247 sb.append("'"); |
|
1248 sb.append(mod.toString()); |
|
1249 sb.append("' "); |
|
1250 } |
|
1251 String key = (list.size() > 1) |
|
1252 ? fatal |
|
1253 ? "jshell.diag.modifier.plural.fatal" |
|
1254 : "jshell.diag.modifier.plural.ignore" |
|
1255 : fatal |
|
1256 ? "jshell.diag.modifier.single.fatal" |
|
1257 : "jshell.diag.modifier.single.ignore"; |
|
1258 String message = state.messageFormat(key, sb.toString().trim()); |
|
1259 return new DiagList(new ModifierDiagnostic(fatal, message, |
|
1260 dis.getStartPosition(modtree), dis.getEndPosition(modtree))); |
|
1261 } |
1249 } |
1262 } |
1250 |
1263 |
1251 String computeDeclareName(TypeSymbol ts) { |
1264 String computeDeclareName(TypeSymbol ts) { |
1252 return Util.JSHELL_ANONYMOUS + "$" + Long.toUnsignedString(anonCount++); |
1265 return Util.JSHELL_ANONYMOUS + "$" + Long.toUnsignedString(anonCount++); |
1253 } |
1266 } |