Skip to content

Commit f7913aa

Browse files
committed
Reprioritize the analysis search path
This change enables behaviors like: - shadowing standard library units with a unit on `DCC_UnitSearchPath` - shadowing `DCC_UnitSearchPath` units with a `DCCReference` unit These cases are somewhat unusual, but they are possible in Delphi.
1 parent 278e7e7 commit f7913aa

File tree

3 files changed

+107
-4
lines changed

3 files changed

+107
-4
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Reprioritize the analysis search path in the following order (highest to lowest):
13+
- Analysis source files (`sonar.sources`)
14+
- Referenced project files (`DCCReference`)
15+
- Search path (`DCC_UnitSearchPath`)
16+
- Debugger source path (`Debugger_DebugSourcePath`)
17+
- Library path (`DelphiLibraryPath`/`DelphiTranslatedLibraryPath`)
18+
- Standard library
19+
20+
1021
## [1.12.2] - 2025-01-06
1122

1223
### Fixed

delphi-frontend/src/main/java/au/com/integradev/delphi/symbol/SymbolTableBuilder.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ private static boolean isPasFile(Path path) {
185185
}
186186

187187
private void createUnitData(Path unitPath, boolean isSourceFile) {
188-
if (unitPaths.add(unitPath) || isSourceFile) {
188+
if (unitPaths.add(unitPath)) {
189189
String unitName = FilenameUtils.getBaseName(unitPath.toString());
190190
UnitData unitData = new UnitData(unitPath, isSourceFile);
191191

@@ -459,10 +459,11 @@ public SymbolTable build() {
459459
throw new SymbolTableConstructionException("typeFactory was not supplied.");
460460
}
461461

462-
processStandardLibrarySearchPaths();
463-
searchPath.getRootDirectories().forEach(this::processSearchPath);
464-
referencedFiles.forEach(file -> this.createUnitData(file, false));
465462
sourceFiles.forEach(file -> this.createUnitData(file, true));
463+
referencedFiles.forEach(file -> this.createUnitData(file, false));
464+
searchPath.getRootDirectories().forEach(this::processSearchPath);
465+
466+
processStandardLibrarySearchPaths();
466467

467468
ProgressReport progressReport =
468469
new ProgressReport(

delphi-frontend/src/test/java/au/com/integradev/delphi/symbol/SymbolTableBuilderTest.java

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
import java.nio.file.spi.FileSystemProvider;
3939
import java.util.List;
4040
import java.util.Set;
41+
import java.util.stream.Collectors;
42+
import java.util.stream.Stream;
4143
import org.junit.jupiter.api.Test;
4244
import org.junit.jupiter.api.io.TempDir;
4345
import org.junit.jupiter.params.ParameterizedTest;
@@ -157,6 +159,95 @@ void testStandardLibrarySearchPathShouldExcludeToolsUnits(
157159
assertThat(symbolTable.getUnitByPath(excludedPath.toString())).isNull();
158160
}
159161

162+
@Test
163+
void testSonarSourcesArePrioritizedOverReferencedFiles(
164+
@TempDir Path standardLibraryPath,
165+
@TempDir Path referencedFilesPath,
166+
@TempDir Path sourceFilesPath)
167+
throws IOException {
168+
createStandardLibrary(standardLibraryPath);
169+
createStandardLibrary(referencedFilesPath);
170+
createStandardLibrary(sourceFilesPath);
171+
172+
List<Path> referencedFiles;
173+
try (Stream<Path> referencedFilesStream = Files.list(referencedFilesPath)) {
174+
referencedFiles = referencedFilesStream.collect(Collectors.toUnmodifiableList());
175+
}
176+
177+
List<Path> sourceFiles;
178+
try (Stream<Path> sourceFilesStream = Files.list(sourceFilesPath)) {
179+
sourceFiles = sourceFilesStream.collect(Collectors.toUnmodifiableList());
180+
}
181+
182+
SymbolTable symbolTable =
183+
SymbolTable.builder()
184+
.preprocessorFactory(new DelphiPreprocessorFactory(Platform.WINDOWS))
185+
.typeFactory(TypeFactoryUtils.defaultFactory())
186+
.standardLibraryPath(standardLibraryPath)
187+
.referencedFiles(referencedFiles)
188+
.sourceFiles(sourceFiles)
189+
.build();
190+
191+
assertThat(symbolTable.getUnitByPath(standardLibraryPath.resolve("SysInit.pas").toString()))
192+
.isNull();
193+
assertThat(symbolTable.getUnitByPath(referencedFilesPath.resolve("SysInit.pas").toString()))
194+
.isNull();
195+
assertThat(symbolTable.getUnitByPath(sourceFilesPath.resolve("SysInit.pas").toString()))
196+
.isNotNull();
197+
}
198+
199+
@Test
200+
void testReferencedFilesArePrioritizedOverSearchPath(
201+
@TempDir Path standardLibraryPath,
202+
@TempDir Path searchPathRoot,
203+
@TempDir Path referencedFilesPath)
204+
throws IOException {
205+
createStandardLibrary(standardLibraryPath);
206+
createStandardLibrary(searchPathRoot);
207+
createStandardLibrary(referencedFilesPath);
208+
209+
List<Path> referencedFiles;
210+
try (Stream<Path> referencedFilesStream = Files.list(referencedFilesPath)) {
211+
referencedFiles = referencedFilesStream.collect(Collectors.toUnmodifiableList());
212+
}
213+
214+
SymbolTable symbolTable =
215+
SymbolTable.builder()
216+
.preprocessorFactory(new DelphiPreprocessorFactory(Platform.WINDOWS))
217+
.typeFactory(TypeFactoryUtils.defaultFactory())
218+
.standardLibraryPath(standardLibraryPath)
219+
.searchPath(SearchPath.create(List.of(searchPathRoot)))
220+
.referencedFiles(referencedFiles)
221+
.build();
222+
223+
assertThat(symbolTable.getUnitByPath(standardLibraryPath.resolve("SysInit.pas").toString()))
224+
.isNull();
225+
assertThat(symbolTable.getUnitByPath(searchPathRoot.resolve("SysInit.pas").toString()))
226+
.isNull();
227+
assertThat(symbolTable.getUnitByPath(referencedFilesPath.resolve("SysInit.pas").toString()))
228+
.isNotNull();
229+
}
230+
231+
@Test
232+
void testSearchPathIsPrioritizedOverStandardLibrary(
233+
@TempDir Path standardLibraryPath, @TempDir Path searchPathRoot) throws IOException {
234+
createStandardLibrary(standardLibraryPath);
235+
createStandardLibrary(searchPathRoot);
236+
237+
SymbolTable symbolTable =
238+
SymbolTable.builder()
239+
.preprocessorFactory(new DelphiPreprocessorFactory(Platform.WINDOWS))
240+
.typeFactory(TypeFactoryUtils.defaultFactory())
241+
.standardLibraryPath(standardLibraryPath)
242+
.searchPath(SearchPath.create(List.of(searchPathRoot)))
243+
.build();
244+
245+
assertThat(symbolTable.getUnitByPath(standardLibraryPath.resolve("SysInit.pas").toString()))
246+
.isNull();
247+
assertThat(symbolTable.getUnitByPath(searchPathRoot.resolve("SysInit.pas").toString()))
248+
.isNotNull();
249+
}
250+
160251
@ParameterizedTest
161252
@ValueSource(strings = {"#$@", "unit ErrorUnit;"})
162253
void testRecognitionErrorInImportShouldNotThrow(

0 commit comments

Comments
 (0)