Skip to content

Commit

Permalink
handle this and static scopes
Browse files Browse the repository at this point in the history
  • Loading branch information
softwareCobbler committed Feb 19, 2024
1 parent cd2a861 commit 63c10af
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 13 deletions.
12 changes: 2 additions & 10 deletions luceedebug/src/main/java/luceedebug/coreinject/CfEntityRef.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,6 @@ public IDebugEntity[] getAsDebugEntity(IDebugEntity.DebugEntityType maybeNull_wh
final boolean namedOK = maybeNull_which == null || maybeNull_which == IDebugEntity.DebugEntityType.NAMED;
final boolean indexedOK = maybeNull_which == null || maybeNull_which == IDebugEntity.DebugEntityType.INDEXED;

if (cfEntity.wrapped instanceof Component && namedOK) {
@SuppressWarnings("unchecked")
var m = (Map<String, Object>)((Component)cfEntity.wrapped).getComponentScope();
return getAsMaplike(m);
}
if (cfEntity.wrapped instanceof Map && namedOK) {
@SuppressWarnings("unchecked")
var m = (Map<String, Object>)cfEntity.wrapped;
Expand All @@ -84,11 +79,8 @@ private IDebugEntity[] getAsMaplike(Map<String, Object> map) {

Set<Map.Entry<String,Object>> entries = map.entrySet();

// cfc<Foo> {m1: thing, m2: thing, this: cfc<Foo>}
// expanding 'this' -> {m1: thing, getM1: lucee.runtime.type.UDFGetter, m2: thing, ...}
// If expanding "this", show functionLikes,
// otherwise, we're expanding a direct ref, and we don't want to show functionLikes
final var skipFunctionLikes = map instanceof lucee.runtime.ComponentScope && !this.name.toLowerCase().equals("this");
// We had been showing member functions on component instances, but it's really just noise. Maybe this could be a configurable option.
final var skipFunctionLikes = true;

for (Map.Entry<String, Object> entry : entries) {
IDebugEntity val = maybeNull_asValue(entry.getKey(), entry.getValue(), skipFunctionLikes);
Expand Down
30 changes: 28 additions & 2 deletions luceedebug/src/main/java/luceedebug/coreinject/DebugFrame.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
Expand Down Expand Up @@ -89,6 +90,9 @@ static class FrameContext {
final lucee.runtime.type.scope.Scope server;
final lucee.runtime.type.scope.Scope url;
final lucee.runtime.type.scope.Variables variables;
// n.b. the `this` scope does not derive from Scope
final lucee.runtime.type.Struct this_;
final lucee.runtime.type.scope.Scope static_;

// lazy init because it (might?) be expensive to walk scope chains eagerly every frame
private ArrayList<lucee.runtime.type.scope.ClosureScope> capturedScopeChain = null;
Expand All @@ -113,6 +117,27 @@ static class FrameContext {
this.server = getScopelikeOrNull(() -> pageContext.serverScope());
this.url = getScopelikeOrNull(() -> pageContext.urlScope());
this.variables = getScopelikeOrNull(() -> pageContext.variablesScope());
this.this_ = getScopelikeOrNull(() -> {
// there is also `PageContextImpl.thisGet()` but it can create a `this` property on the variables scope, which seems like
// something we don't want to do, since it mutates the user's scopes instead of just reading from them.
if (this.variables instanceof lucee.runtime.ComponentScope) {
// The `this` scope IS the component, bound to the variables scope that is an instanceof ComponentScope
// (which means ComponentScope is a variables scope containing a THIS scope, rather than ComponentScope IS the this scope)
// Alternatively we could just lookup the `this` property on `variables`.
return ((lucee.runtime.ComponentScope)this.variables).getComponent();
}
else if (this.variables instanceof lucee.runtime.type.scope.ClosureScope) {
// A closure scope is a variables scope wrapper containing a variable scope.
// Probably we could test here for if the closureScope contains a component scope, but just looking for `this` seems to be fine.
return (lucee.runtime.type.Struct)this.variables.get("this");
}
else {
return null;
}
});

// If we have a `this` scope, meaning we are in a component, then we should have a static scope.
this.static_ = this.this_ instanceof lucee.runtime.Component ? ((lucee.runtime.Component)this.this_).staticScope() : null;
}

public ArrayList<lucee.runtime.type.scope.ClosureScope> getCapturedScopeChain() {
Expand Down Expand Up @@ -223,8 +248,7 @@ private static String tryGetFrameName(PageContext pageContext) {
return frameName;
}

private void checkedPutScopeRef(String name, lucee.runtime.type.scope.Scope scope) {

private void checkedPutScopeRef(String name, Map<?,?> scope) {
if (scope != null && !(scope instanceof LocalNotSupportedScope)) {
scopes_.put(name, CfEntityRef.freshRef(valTracker, refTracker, name, scope));
}
Expand All @@ -243,7 +267,9 @@ private void lazyInitScopeRefs() {
checkedPutScopeRef("local", frameContext_.local);
checkedPutScopeRef("request", frameContext_.request);
checkedPutScopeRef("session", frameContext_.session);
checkedPutScopeRef("static", frameContext_.static_);
checkedPutScopeRef("server", frameContext_.server);
checkedPutScopeRef("this", frameContext_.this_);
checkedPutScopeRef("url", frameContext_.url);
checkedPutScopeRef("variables", frameContext_.variables);

Expand Down
10 changes: 9 additions & 1 deletion luceedebug/src/main/java/luceedebug/instrumenter/CfmOrCfc.java
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,15 @@ public MethodVisitor visitMethod(
// e.g. `udfCall` is an empty method with zero bytecodes, but `udfCall1` is non-empty, etc.


if (!isWrappingMethod && (name.equals("call") || name.startsWith("udfCall") || name.equals("initComponent") || name.equals("newInstance") || name.equals("threadCall") || name.startsWith("udfDefaultValue"))) {
if (!isWrappingMethod && (
name.equals("call")
|| name.startsWith("udfCall")
|| name.equals("initComponent")
|| name.equals("newInstance")
|| name.equals("threadCall")
|| name.startsWith("udfDefaultValue")
|| name.equals("staticConstructor")
)) {
final String delegateToName = "__luceedebug__" + name;
createWrapperMethod(access, name, descriptor, signature, exceptions, delegateToName);

Expand Down

0 comments on commit 63c10af

Please sign in to comment.