Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
public class DebugAdapterContext implements IDebugAdapterContext {
private static final int MAX_CACHE_ITEMS = 10000;
private final StepFilters defaultFilters = new StepFilters();
private Map<String, String> sourceMappingCache = Collections.synchronizedMap(new LRUCache<>(MAX_CACHE_ITEMS));
private Map<String, Source> sourceMappingCache = Collections.synchronizedMap(new LRUCache<>(MAX_CACHE_ITEMS));
private IProviderContext providerContext;
private IProtocolServer server;

Expand Down Expand Up @@ -212,7 +212,7 @@ public void setVariableFormatter(IVariableFormatter variableFormatter) {
}

@Override
public Map<String, String> getSourceLookupCache() {
public Map<String, Source> getSourceLookupCache() {
return sourceMappingCache;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public interface IDebugAdapterContext {

void setVariableFormatter(IVariableFormatter variableFormatter);

Map<String, String> getSourceLookupCache();
Map<String, Source> getSourceLookupCache();

void setDebuggeeEncoding(Charset encoding);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core.adapter;

import java.util.List;
Expand Down Expand Up @@ -42,18 +41,31 @@ public interface ISourceLookUpProvider extends IProvider {
JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceBreakpoint[] sourceBreakpoints) throws DebugException;

/**
* Given a fully qualified class name and source file path, search the associated disk source file.
*
* @param fullyQualifiedName
* the fully qualified class name (e.g. com.microsoft.java.debug.core.adapter.ISourceLookUpProvider).
* @param sourcePath
* the qualified source file path (e.g. com\microsoft\java\debug\core\adapter\ISourceLookupProvider.java).
* @return the associated source file uri.
* Deprecated, please use {@link #getSource(String, String)} instead.
*/
@Deprecated
String getSourceFileURI(String fullyQualifiedName, String sourcePath);

String getSourceContents(String uri);

/**
* Retrieves a {@link Source} object representing the source code associated with the given fully qualified class name and source file path.
* The implementation of this interface can determine a source is "local" or "remote".
* In case of "remote" a follow up "source" request will be issued by the client
*
* @param fullyQualifiedName
* the fully qualified class name,
* e.g., "com.microsoft.java.debug.core.adapter.ISourceLookUpProvider".
* @param sourcePath
* the qualified source file path,
* e.g., "com/microsoft/java/debug/core/adapter/ISourceLookupProvider.java".
* @return A {@link Source} object encapsulating the source file URI obtained from
* {@link #getSourceFileURI(String, String)} and the source type as {@link SourceType#LOCAL}.
*/
default Source getSource(String fullyQualifiedName, String sourcePath) {
return new Source(getSourceFileURI(fullyQualifiedName, sourcePath), SourceType.LOCAL);
}

/**
* Returns the Java runtime that the specified project's build path used.
* @param projectName
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/

package com.microsoft.java.debug.core.adapter;

public class Source {
public final String uri;
public final SourceType type;

public Source(String uri, SourceType type) {
this.uri = uri;
this.type = type;
}

public String getUri() {
return this.uri;
}

public SourceType getType() {
return this.type;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*******************************************************************************
* Copyright (c) 2017 Microsoft Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Microsoft Corporation - initial API and implementation
*******************************************************************************/
package com.microsoft.java.debug.core.adapter;

public enum SourceType {
REMOTE,
LOCAL
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import com.microsoft.java.debug.core.adapter.IDebugAdapterContext;
import com.microsoft.java.debug.core.adapter.IDebugRequestHandler;
import com.microsoft.java.debug.core.adapter.ISourceLookUpProvider;
import com.microsoft.java.debug.core.adapter.Source;
import com.microsoft.java.debug.core.adapter.SourceType;
import com.microsoft.java.debug.core.adapter.formatter.SimpleTypeFormatter;
import com.microsoft.java.debug.core.adapter.variables.StackFrameReference;
import com.microsoft.java.debug.core.protocol.Messages.Response;
Expand Down Expand Up @@ -141,7 +143,7 @@ public CompletableFuture<Response> handle(Command command, Arguments arguments,
}

private static List<StackFrameInfo> resolveStackFrameInfos(StackFrame[] frames, boolean async)
throws AbsentInformationException, IncompatibleThreadStateException {
throws AbsentInformationException, IncompatibleThreadStateException {
List<StackFrameInfo> jdiFrames = new ArrayList<>();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (StackFrame frame : frames) {
Expand Down Expand Up @@ -221,7 +223,7 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra
clientSource = null;
}
} else if (DebugSettings.getCurrent().debugSupportOnDecompiledSource == Switch.ON
&& clientSource != null && clientSource.path != null) {
&& clientSource != null && clientSource.path != null) {
// Align the original line with the decompiled line.
int[] lineMappings = context.getProvider(ISourceLookUpProvider.class).getOriginalLineMappings(clientSource.path);
int[] renderLines = AdapterUtils.binarySearchMappedLines(lineMappings, clientLineNumber);
Expand All @@ -244,7 +246,7 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra
});
if (match) {
clientColumnNumber = AdapterUtils.convertColumnNumber(breakpoint.getColumnNumber(),
context.isDebuggerColumnsStartAt1(), context.isClientColumnsStartAt1());
context.isDebuggerColumnsStartAt1(), context.isClientColumnsStartAt1());
}
}
}
Expand All @@ -256,33 +258,44 @@ private Types.StackFrame convertDebuggerStackFrameToClient(StackFrameInfo jdiFra
/**
* Find the source mapping for the specified source file name.
*/
public static Types.Source convertDebuggerSourceToClient(String fullyQualifiedName, String sourceName, String relativeSourcePath,
public static Types.Source convertDebuggerSourceToClient(String fullyQualifiedName, String sourceName,
String relativeSourcePath,
IDebugAdapterContext context) throws URISyntaxException {

// use a lru cache for better performance
String uri = context.getSourceLookupCache().computeIfAbsent(fullyQualifiedName, key -> {
String fromProvider = context.getProvider(ISourceLookUpProvider.class).getSourceFileURI(key, relativeSourcePath);
// avoid return null which will cause the compute function executed again
return StringUtils.isBlank(fromProvider) ? "" : fromProvider;
Source source = context.getSourceLookupCache().computeIfAbsent(fullyQualifiedName, key -> {
Source result = context.getProvider(ISourceLookUpProvider.class).getSource(key, relativeSourcePath);
if (result == null) {
return new Source("", SourceType.LOCAL);
}
return result;
});

Integer sourceReference = 0;
String uri = source.getUri();

if (source.getType().equals(SourceType.REMOTE)) {
sourceReference = context.createSourceReference(source.getUri());
}

if (!StringUtils.isBlank(uri)) {
// The Source.path could be a file system path or uri string.
if (uri.startsWith("file:")) {
String clientPath = AdapterUtils.convertPath(uri, context.isDebuggerPathsAreUri(), context.isClientPathsAreUri());
return new Types.Source(sourceName, clientPath, 0);
return new Types.Source(sourceName, clientPath, sourceReference);
} else {
// If the debugger returns uri in the Source.path for the StackTrace response, VSCode client will try to find a TextDocumentContentProvider
// to render the contents.
// Language Support for Java by Red Hat extension has already registered a jdt TextDocumentContentProvider to parse the jdt-based uri.
// The jdt uri looks like 'jdt://contents/rt.jar/java.io/PrintStream.class?=1.helloworld/%5C/usr%5C/lib%5C/jvm%5C/java-8-oracle%5C/jre%5C/
// lib%5C/rt.jar%3Cjava.io(PrintStream.class'.
return new Types.Source(sourceName, uri, 0);
return new Types.Source(sourceName, uri, sourceReference);
}
} else {
// If the source lookup engine cannot find the source file, then lookup it in the source directories specified by user.
String absoluteSourcepath = AdapterUtils.sourceLookup(context.getSourcePaths(), relativeSourcePath);
if (absoluteSourcepath != null) {
return new Types.Source(sourceName, absoluteSourcepath, 0);
return new Types.Source(sourceName, absoluteSourcepath, sourceReference);
} else {
return null;
}
Expand Down