5656import org .eclipse .jdt .core .dom .IMethodBinding ;
5757import org .eclipse .jdt .core .dom .ITypeBinding ;
5858import org .eclipse .jdt .core .dom .LambdaExpression ;
59+ import org .eclipse .jdt .core .dom .SimpleName ;
5960import org .eclipse .jdt .core .manipulation .CoreASTProvider ;
6061import org .eclipse .jdt .internal .core .JarPackageFragmentRoot ;
6162import org .eclipse .jdt .launching .IVMInstall ;
7273import com .microsoft .java .debug .core .Configuration ;
7374import com .microsoft .java .debug .core .DebugException ;
7475import com .microsoft .java .debug .core .DebugSettings ;
75- import com .microsoft .java .debug .core .JavaBreakpointLocation ;
7676import com .microsoft .java .debug .core .DebugSettings .Switch ;
77+ import com .microsoft .java .debug .core .JavaBreakpointLocation ;
7778import com .microsoft .java .debug .core .adapter .AdapterUtils ;
7879import com .microsoft .java .debug .core .adapter .Constants ;
7980import com .microsoft .java .debug .core .adapter .IDebugAdapterContext ;
@@ -167,11 +168,13 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
167168 return new JavaBreakpointLocation [0 ];
168169 }
169170
170- CompilationUnit astUnit = asCompilationUnit (sourceUri );
171+ CompilationUnitResult result = asCompilationUnit (sourceUri );
172+ CompilationUnit astUnit = (result != null ) ? result .compilationUnit : null ;
171173 JavaBreakpointLocation [] sourceLocations = Stream .of (sourceBreakpoints )
172174 .map (sourceBreakpoint -> new JavaBreakpointLocation (sourceBreakpoint .line , sourceBreakpoint .column ))
173175 .toArray (JavaBreakpointLocation []::new );
174176 if (astUnit != null ) {
177+ final String source = result .source ;
175178 Map <Integer , BreakpointLocation []> resolvedLocations = new HashMap <>();
176179 for (JavaBreakpointLocation sourceLocation : sourceLocations ) {
177180 int sourceLine = sourceLocation .lineNumber ();
@@ -190,7 +193,8 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
190193 if (resolvedLocations .containsKey (sourceLine )) {
191194 sourceLocation .setAvailableBreakpointLocations (resolvedLocations .get (sourceLine ));
192195 } else {
193- BreakpointLocation [] inlineLocations = getInlineBreakpointLocations (astUnit , sourceLine );
196+ BreakpointLocation [] inlineLocations = getInlineBreakpointLocations (astUnit , sourceLine ,
197+ source );
194198 sourceLocation .setAvailableBreakpointLocations (inlineLocations );
195199 resolvedLocations .put (sourceLine , inlineLocations );
196200 }
@@ -223,7 +227,8 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
223227 if (resolvedLocations .containsKey (sourceLine )) {
224228 sourceLocation .setAvailableBreakpointLocations (resolvedLocations .get (sourceLine ));
225229 } else {
226- BreakpointLocation [] inlineLocations = getInlineBreakpointLocations (astUnit , sourceLine );
230+ BreakpointLocation [] inlineLocations = getInlineBreakpointLocations (astUnit , sourceLine ,
231+ source );
227232 sourceLocation .setAvailableBreakpointLocations (inlineLocations );
228233 resolvedLocations .put (sourceLine , inlineLocations );
229234 }
@@ -238,7 +243,8 @@ public JavaBreakpointLocation[] getBreakpointLocations(String sourceUri, SourceB
238243 return sourceLocations ;
239244 }
240245
241- private BreakpointLocation [] getInlineBreakpointLocations (final CompilationUnit astUnit , int sourceLine ) {
246+ private BreakpointLocation [] getInlineBreakpointLocations (final CompilationUnit astUnit , int sourceLine ,
247+ String source ) {
242248 List <BreakpointLocation > locations = new ArrayList <>();
243249 // The starting position of each line is the default breakpoint location for
244250 // that line.
@@ -255,6 +261,23 @@ public boolean visit(LambdaExpression node) {
255261 int endColumn = astUnit .getColumnNumber (lambdaEnd );
256262 BreakpointLocation location = new BreakpointLocation (startLine , startColumn , endLine , endColumn );
257263 locations .add (location );
264+ } else if (sourceLine < startLine && node .getParent () != null ) {
265+ ASTNode parent = node .getParent ();
266+ if (astUnit .getLineNumber (parent .getStartPosition ()) == sourceLine &&
267+ parent instanceof org .eclipse .jdt .core .dom .MethodInvocation ) {
268+ org .eclipse .jdt .core .dom .MethodInvocation methodInvc = (org .eclipse .jdt .core .dom .MethodInvocation ) parent ;
269+ SimpleName name = methodInvc .getName ();
270+ int nameEnd = name .getStartPosition () + name .getLength ();
271+ if (hasOnlyWhitespaceInBetween (nameEnd + 1 , lambdaStart , source )) {
272+ int lambdaEnd = lambdaStart + node .getLength ();
273+ int startColumn = astUnit .getColumnNumber (lambdaStart );
274+ int endLine = astUnit .getLineNumber (lambdaEnd );
275+ int endColumn = astUnit .getColumnNumber (lambdaEnd );
276+ BreakpointLocation location = new BreakpointLocation (startLine , startColumn , endLine ,
277+ endColumn );
278+ locations .add (location );
279+ }
280+ }
258281 }
259282 return super .visit (node );
260283 }
@@ -263,12 +286,12 @@ public boolean visit(LambdaExpression node) {
263286 return locations .toArray (BreakpointLocation []::new );
264287 }
265288
266- private CompilationUnit asCompilationUnit (String uri ) {
289+ private CompilationUnitResult asCompilationUnit (String uri ) {
267290 final ASTParser parser = ASTParser .newParser (this .latestASTLevel );
268291 parser .setResolveBindings (true );
269292 parser .setBindingsRecovery (true );
270293 parser .setStatementsRecovery (true );
271- CompilationUnit astUnit = null ;
294+ CompilationUnitResult astUnit = null ;
272295 String filePath = AdapterUtils .toPath (uri );
273296 // For file uri, read the file contents directly and pass them to the ast
274297 // parser.
@@ -305,15 +328,15 @@ private CompilationUnit asCompilationUnit(String uri) {
305328 parser .setCompilerOptions (javaOptions );
306329 }
307330 parser .setUnitName (Paths .get (filePath ).getFileName ().toString ());
308- astUnit = ( CompilationUnit ) parser .createAST (null );
331+ astUnit = new CompilationUnitResult (( CompilationUnit ) parser .createAST (null ), source );
309332 } else {
310333 // For non-file uri (e.g. jdt://contents/rt.jar/java.io/PrintStream.class),
311334 // leverage jdt to load the source contents.
312335 IClassFile typeRoot = resolveClassFile (uri );
313336 try {
314337 if (typeRoot != null && typeRoot .getSourceRange () != null ) {
315338 parser .setSource (typeRoot );
316- astUnit = ( CompilationUnit ) parser .createAST (null );
339+ astUnit = new CompilationUnitResult (( CompilationUnit ) parser .createAST (null ), typeRoot . getSource () );
317340 } else if (typeRoot != null && DebugSettings .getCurrent ().debugSupportOnDecompiledSource == Switch .ON ) {
318341 ContentProviderManager contentProvider = JavaLanguageServerPlugin .getContentProviderManager ();
319342 try {
@@ -337,7 +360,7 @@ private CompilationUnit asCompilationUnit(String uri) {
337360 }
338361 parser .setUnitName (typeRoot .getElementName ());
339362 parser .setSource (contents .toCharArray ());
340- astUnit = ( CompilationUnit ) parser .createAST (null );
363+ astUnit = new CompilationUnitResult (( CompilationUnit ) parser .createAST (null ), contents );
341364 }
342365 } catch (Exception e ) {
343366 JavaLanguageServerPlugin .logException (e .getMessage (), e );
@@ -350,6 +373,13 @@ private CompilationUnit asCompilationUnit(String uri) {
350373 return astUnit ;
351374 }
352375
376+ private boolean hasOnlyWhitespaceInBetween (int start , int end , String source ) {
377+ if (source != null && start < end && source .length () >= end ) {
378+ return source .substring (start , end ).isBlank ();
379+ }
380+ return false ;
381+ }
382+
353383 @ Override
354384 public String getSourceFileURI (String fullyQualifiedName , String sourcePath ) {
355385 if (sourcePath == null ) {
@@ -518,7 +548,7 @@ public List<MethodInvocation> findMethodInvocations(String uri, int line) {
518548 }
519549 }
520550
521- final CompilationUnit astUnit = useCache ? cachedUnit : asCompilationUnit (uri );
551+ final CompilationUnit astUnit = useCache ? cachedUnit : asCompilationUnit (uri ). compilationUnit ;
522552 if (astUnit == null ) {
523553 return Collections .emptyList ();
524554 }
@@ -579,7 +609,8 @@ public int[] getOriginalLineMappings(String uri) {
579609 return null ;
580610 }
581611
582- IPackageFragmentRoot packageRoot = (IPackageFragmentRoot ) classFile .getAncestor (IJavaElement .PACKAGE_FRAGMENT_ROOT );
612+ IPackageFragmentRoot packageRoot = (IPackageFragmentRoot ) classFile
613+ .getAncestor (IJavaElement .PACKAGE_FRAGMENT_ROOT );
583614 if (packageRoot != null && packageRoot .getSourceAttachmentPath () != null ) {
584615 return null ;
585616 }
@@ -625,4 +656,14 @@ public int[] getDecompiledLineMappings(String uri) {
625656
626657 return null ;
627658 }
659+
660+ public static class CompilationUnitResult {
661+ public CompilationUnit compilationUnit ;
662+ public String source ;
663+
664+ public CompilationUnitResult (CompilationUnit compilationUnit , String source ) {
665+ this .compilationUnit = compilationUnit ;
666+ this .source = source ;
667+ }
668+ }
628669}
0 commit comments