6565import com .sun .jdi .StringReference ;
6666import com .sun .jdi .Type ;
6767import com .sun .jdi .Value ;
68+ import com .sun .jdi .PrimitiveType ;
69+ import com .sun .jdi .ClassNotLoadedException ;
6870
6971public class VariablesRequestHandler implements IDebugRequestHandler {
7072 protected static final Logger logger = Logger .getLogger (Configuration .LOGGER_NAME );
@@ -82,7 +84,7 @@ public class VariablesRequestHandler implements IDebugRequestHandler {
8284 * single-threaded JDWP request processing strategy,
8385 * a single JDWP latency is about 10ms.
8486 */
85- static final long USABLE_JDWP_LATENCY = 10 /** ms*/ ;
87+ static final long USABLE_JDWP_LATENCY = 10 /*ms*/ ;
8688
8789 @ Override
8890 public List <Command > getTargetCommands () {
@@ -370,10 +372,12 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
370372 referenceId = context .getRecyclableIdPool ().addObject (containerNode .getThreadId (), varProxy );
371373 }
372374
375+ String [] rawAttributes = extractAttributes (javaVariable );
376+
373377 Types .Variable typedVariables = new Types .Variable (name , valueString , typeString , referenceId , evaluateName );
374378 typedVariables .indexedVariables = Math .max (indexedVariables , 0 );
375- if (varProxy != null && varProxy .isLazyVariable ()) {
376- typedVariables .presentationHint = new VariablePresentationHint (true );
379+ if (( varProxy != null && varProxy .isLazyVariable ()) || ( rawAttributes . length > 0 )) {
380+ typedVariables .presentationHint = new VariablePresentationHint (varProxy != null && varProxy . isLazyVariable (), rawAttributes );
377381 }
378382
379383 if (detailsValue != null ) {
@@ -391,6 +395,36 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
391395 return CompletableFuture .completedFuture (response );
392396 }
393397
398+ private String [] extractAttributes (Variable variable ) {
399+ final List <String > attributes = new ArrayList <>();
400+ if (variable .field != null ) {
401+ if (variable .field .isStatic ()) {
402+ attributes .add ("static" );
403+ }
404+ if (variable .field .isFinal ()) {
405+ // static final Primitive or StringRef fields are compile-time constants in Java
406+ boolean isPrimitive ;
407+ try {
408+ isPrimitive = variable .field .type () instanceof PrimitiveType ;
409+ } catch (ClassNotLoadedException e ) { /* type() not yet loaded indicates some ReferenceType */
410+ isPrimitive = false ;
411+ }
412+ boolean canBeTrueConstant = (isPrimitive || variable .field instanceof StringReference );
413+ if (variable .field .isStatic () && canBeTrueConstant ) {
414+ attributes .add ("constant" );
415+ }
416+ attributes .add ("readOnly" );
417+ }
418+ }
419+ // local 'final' variables get inlined by the compiler and do not appear
420+
421+ if (variable .value instanceof StringReference ) {
422+ attributes .add ("rawString" );
423+ }
424+
425+ return attributes .toArray (new String [0 ]);
426+ }
427+
394428 private boolean supportsLogicStructureView (IDebugAdapterContext context ) {
395429 return (!useAsyncJDWP (context ) || context .getJDWPLatency () <= USABLE_JDWP_LATENCY )
396430 && DebugSettings .getCurrent ().showLogicalStructure ;
0 commit comments