Skip to content

Commit 04498ef

Browse files
DocSymbol Work: range and selectionRange tweaks (#88)
* fix: docSymbol range and selectionRange accuracy increased * fix: lint * fix: moving kindmap out of the function * fix: better ranges * fix: rename prop method and fix some logger issues * fix: moving typecheck into the symbol definition * fix: range calcs and test * fix: remove textdoc * fix: more cleanup * fix: logger fix for improved performance * chore: review suggestions in pr form (#93) chore: review sugestions in pr form @W-18895479@ * fix: updating name * fix: partial syms when we run into lexer or parser errors (#91) * fix: partial syms when we run into lexer or parser errors * fix: logger fix for improved performance * fix: remove unused getCompilationUnit method * fix: using the qualifiedName id for selectionRange on constructor methods * feat: tests for the new id location detector in constructor * fix: end ranges are exclusive so this needed to be increased by one * feat: license text and fixed error log * fix: workaround for constructor --------- Co-authored-by: peternhale <[email protected]>
1 parent f251137 commit 04498ef

File tree

11 files changed

+2071
-272
lines changed

11 files changed

+2071
-272
lines changed

LICENSE.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
BSD 3-Clause License
2-
31
Copyright (c) 2025, Salesforce, Inc.
42
All rights reserved.
53

@@ -21,9 +19,10 @@ THIS SOFTWARE IS PROVIDED BY SALESFORCE AND CONTRIBUTORS "AS IS"
2119
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2220
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2321
DISCLAIMED. IN NO EVENT SHALL SALESFORCE OR CONTRIBUTORS BE LIABLE
22+
2423
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2524
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2625
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2726
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2827
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29-
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

packages/apex-parser-ast/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export * from './utils/PlatformUtils';
4444

4545
// Export utils
4646
export * from './utils/AnnotationUtils';
47+
export * from './utils/symbolNarrowing';
4748

4849
// Export semantic validators
4950
export * from './semantics/modifiers/index';

packages/apex-parser-ast/src/parser/compilerService.ts

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* repo root or https://opensource.org/licenses/BSD-3-Clause
77
*/
88

9-
import { CharStreams, CommonTokenStream } from 'antlr4ts';
9+
import { CharStreams, CommonTokenStream, DefaultErrorStrategy } from 'antlr4ts';
1010
import {
1111
ApexLexer,
1212
ApexParser,
@@ -56,6 +56,18 @@ export interface CompilationResultWithAssociations<T>
5656
commentAssociations: CommentAssociation[];
5757
}
5858

59+
/**
60+
* Result of creating a parse tree.
61+
*/
62+
export interface ParseTreeResult {
63+
fileName: string;
64+
parseTree: CompilationUnitContext | TriggerUnitContext;
65+
errorListener: ApexErrorListener;
66+
lexer: ApexLexer;
67+
tokenStream: CommonTokenStream;
68+
parser: ApexParser;
69+
}
70+
5971
/**
6072
* Options for compilation behavior
6173
*/
@@ -89,6 +101,52 @@ export class CompilerService {
89101
);
90102
}
91103

104+
/**
105+
* Creates a parse tree from the given file content.
106+
* This method handles the setup of the lexer, parser, and error listeners.
107+
* @param fileContent The content of the Apex file.
108+
* @param fileName The name of the file, used for error reporting and trigger detection.
109+
* @returns A ParseTreeResult containing the parse tree and related objects.
110+
*/
111+
private createParseTree(
112+
fileContent: string,
113+
fileName: string = 'unknown.cls',
114+
): ParseTreeResult {
115+
this.logger.debug(() => `Creating parse tree for ${fileName}`);
116+
117+
// Create error listener
118+
const errorListener = new ApexErrorListener(fileName);
119+
120+
// Set up parsing infrastructure
121+
const inputStream = CharStreams.fromString(fileContent);
122+
const lexer = new ApexLexer(new CaseInsensitiveInputStream(inputStream));
123+
const tokenStream = new CommonTokenStream(lexer);
124+
const parser = new ApexParser(tokenStream);
125+
parser.errorHandler = new DefaultErrorStrategy();
126+
127+
// Set up error listeners
128+
parser.removeErrorListeners();
129+
lexer.removeErrorListeners();
130+
parser.addErrorListener(errorListener);
131+
const lexerErrorListener = new ApexLexerErrorListener(errorListener);
132+
lexer.addErrorListener(lexerErrorListener);
133+
134+
// Parse the compilation unit
135+
const isTrigger = fileName.endsWith('.trigger');
136+
const parseTree = isTrigger
137+
? parser.triggerUnit()
138+
: parser.compilationUnit();
139+
140+
return {
141+
fileName,
142+
parseTree,
143+
errorListener,
144+
lexer,
145+
tokenStream,
146+
parser,
147+
};
148+
}
149+
92150
/**
93151
* Parse and compile a single Apex file.
94152
* @param fileContent The content of the Apex file to parse
@@ -109,8 +167,11 @@ export class CompilerService {
109167
this.logger.debug(() => `Starting compilation of ${fileName}`);
110168

111169
try {
112-
// Create error listener
113-
const errorListener = new ApexErrorListener(fileName);
170+
// Create parse tree and get associated components
171+
const { parseTree, errorListener, tokenStream } = this.createParseTree(
172+
fileContent,
173+
fileName,
174+
);
114175

115176
// Create comment collector by default (opt-out behavior)
116177
let commentCollector: ApexCommentCollectorListener | null = null;
@@ -120,19 +181,6 @@ export class CompilerService {
120181
);
121182
}
122183

123-
// Set up parsing infrastructure
124-
const inputStream = CharStreams.fromString(fileContent);
125-
const lexer = new ApexLexer(new CaseInsensitiveInputStream(inputStream));
126-
const tokenStream = new CommonTokenStream(lexer);
127-
const parser = new ApexParser(tokenStream);
128-
129-
// Set up error listeners
130-
parser.removeErrorListeners();
131-
lexer.removeErrorListeners();
132-
parser.addErrorListener(errorListener);
133-
const lexerErrorListener = new ApexLexerErrorListener(errorListener);
134-
lexer.addErrorListener(lexerErrorListener);
135-
136184
// Set up the main listener
137185
listener.setErrorListener(errorListener);
138186
const namespace = options.projectNamespace || this.projectNamespace;
@@ -146,20 +194,14 @@ export class CompilerService {
146194
commentCollector.setTokenStream(tokenStream);
147195
}
148196

149-
// Parse the compilation unit
150-
const isTrigger = fileName.endsWith('.trigger');
151-
const compilationUnitContext = isTrigger
152-
? parser.triggerUnit()
153-
: parser.compilationUnit();
154-
155197
// Walk the tree with the main listener
156198
const walker = new ParseTreeWalker();
157-
walker.walk(listener, compilationUnitContext);
199+
walker.walk(listener, parseTree);
158200

159201
// Walk the tree with comment collector if requested
160202
let comments: ApexComment[] = [];
161203
if (commentCollector) {
162-
walker.walk(commentCollector, compilationUnitContext);
204+
walker.walk(commentCollector, parseTree);
163205
comments = commentCollector.getResult();
164206
}
165207

@@ -404,40 +446,4 @@ export class CompilerService {
404446

405447
return results;
406448
}
407-
408-
private getCompilationUnit(
409-
source: string,
410-
errorListener?: ApexErrorListener,
411-
): CompilationUnitContext | TriggerUnitContext {
412-
this.logger.debug('Creating compilation unit');
413-
const inputStream = CharStreams.fromString(source);
414-
const lexer = new ApexLexer(new CaseInsensitiveInputStream(inputStream));
415-
const tokenStream = new CommonTokenStream(lexer);
416-
const parser = new ApexParser(tokenStream);
417-
418-
// Add our custom error listener if provided
419-
if (errorListener) {
420-
this.logger.debug('Setting up custom error listeners');
421-
// Remove default error listeners that print to console
422-
parser.removeErrorListeners();
423-
lexer.removeErrorListeners();
424-
425-
// Add our custom error listener
426-
parser.addErrorListener(errorListener);
427-
// Create and add lexer-specific error listener
428-
const lexerErrorListener = new ApexLexerErrorListener(errorListener);
429-
lexer.addErrorListener(lexerErrorListener);
430-
}
431-
432-
// Check if this is a trigger file based on the file extension
433-
const isTrigger =
434-
errorListener?.getFilePath()?.endsWith('.trigger') ?? false;
435-
436-
// Parse the compilation unit or trigger based on file type
437-
this.logger.debug('Parsing compilation unit');
438-
const compilationUnitContext = isTrigger
439-
? parser.triggerUnit()
440-
: parser.compilationUnit();
441-
return compilationUnitContext;
442-
}
443449
}

0 commit comments

Comments
 (0)