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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Changed

- Include the global browsing path in unit import resolution.
- Reprioritize the analysis search path in the following order (highest to lowest):
- Analysis source files (`sonar.sources`)
- Referenced project files (`DCCReference`)
- Search path (`DCC_UnitSearchPath`)
- Debugger source path (`Debugger_DebugSourcePath`)
- Library path (`DelphiLibraryPath`/`DelphiTranslatedLibraryPath`)
- Browsing path (`DelphiBrowsingPath`)
- Standard library

## [1.12.2] - 2025-01-06

### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@ public interface DelphiProject {

List<Path> getDebugSourceDirectories();

List<Path> getLibraryPathDirectories();

List<Path> getBrowsingPathDirectories();

Map<String, String> getUnitAliases();
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ public class DelphiProjectHelper {
private final CompilerVersion compilerVersion;
private final List<Path> searchDirectories;
private final List<Path> debugSourceDirectories;
private final List<Path> libraryPathDirectories;
private final List<Path> browsingPathDirectories;
private final List<Path> referencedFiles;
private final Set<String> conditionalDefines;
private final Set<String> unitScopeNames;
Expand All @@ -93,6 +95,8 @@ public DelphiProjectHelper(
this.compilerVersion = getCompilerVersionFromSettings();
this.searchDirectories = getSearchDirectoriesFromSettings();
this.debugSourceDirectories = new ArrayList<>();
this.libraryPathDirectories = new ArrayList<>();
this.browsingPathDirectories = new ArrayList<>();
this.referencedFiles = new ArrayList<>();
this.conditionalDefines = getPredefinedConditionalDefines();
this.unitScopeNames = getSetFromSettings(DelphiProperties.UNIT_SCOPE_NAMES_KEY);
Expand Down Expand Up @@ -201,6 +205,8 @@ private void indexProjects() {
for (DelphiProject project : projects) {
searchDirectories.addAll(project.getSearchDirectories());
debugSourceDirectories.addAll(project.getDebugSourceDirectories());
libraryPathDirectories.addAll(project.getLibraryPathDirectories());
browsingPathDirectories.addAll(project.getBrowsingPathDirectories());
conditionalDefines.addAll(project.getConditionalDefines());
referencedFiles.addAll(project.getSourceFiles());
unitScopeNames.addAll(project.getUnitScopeNames());
Expand Down Expand Up @@ -310,13 +316,33 @@ public List<Path> getSearchDirectories() {
/**
* Gets the debug source directories specified in project files
*
* @return List of debug source directorie
* @return List of debug source directories
*/
public List<Path> getDebugSourceDirectories() {
indexProjects();
return debugSourceDirectories;
}

/**
* Gets the library path directories specified in project files
*
* @return List of library path directories
*/
public List<Path> getLibraryPathDirectories() {
indexProjects();
return libraryPathDirectories;
}

/**
* Gets the browsing path directories specified in project files
*
* @return List of browsing path directories
*/
public List<Path> getBrowsingPathDirectories() {
indexProjects();
return browsingPathDirectories;
}

/**
* Gets the set of conditional defines specified in settings and project files
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ public DelphiProject parse() {
project.setUnitScopeNames(createUnitScopeNames(result.getProperties()));
project.setSearchDirectories(createSearchDirectories(dprojDirectory, result.getProperties()));
project.setDebugSourceDirectories(createDebugSourceDirectories(result.getProperties()));
project.setLibraryPath(createLibraryPathDirectories(result.getProperties()));
project.setBrowsingPath(createBrowsingPathDirectories(result.getProperties()));
project.setUnitAliases(createUnitAliases(result.getProperties()));
project.setSourceFiles(result.getSourceFiles());

Expand All @@ -81,31 +83,29 @@ private static Set<String> createUnitScopeNames(ProjectProperties properties) {
}

private List<Path> createSearchDirectories(Path dprojDirectory, ProjectProperties properties) {
/*
We manually append the library paths here, even though it's not strictly correct to do so.
List<Path> result = new ArrayList<>();

CodeGear.Delphi.Targets appends the library paths to DCC_UnitSearchPath to create a new
property called UnitSearchPath, which then gets passed through to the compiler.
result.add(dprojDirectory);
result.addAll(createPathList(properties, "DCC_UnitSearchPath"));

However, there are some good reasons not to just read the UnitSearchPath property:
return Collections.unmodifiableList(result);
}

- It would tie us to an implementation detail of the MSBuild glue in CodeGear.Delphi.Targets.
- If the UnitSearchPath property were ever renamed, we'd fall out of compatibility.
- Relying on CodeGear.Delphi.Targets details would require us to mock it up in testing.
*/
private List<Path> createDebugSourceDirectories(ProjectProperties properties) {
return createPathList(properties, "Debugger_DebugSourcePath");
}

List<Path> allPaths = new ArrayList<>();
private List<Path> createLibraryPathDirectories(ProjectProperties properties) {
List<Path> result = new ArrayList<>();

allPaths.add(dprojDirectory);
allPaths.addAll(createPathList(properties, "DCC_UnitSearchPath"));
allPaths.addAll(createPathList(properties, "DelphiLibraryPath", false));
allPaths.addAll(createPathList(properties, "DelphiTranslatedLibraryPath", false));
result.addAll(createPathList(properties, "DelphiLibraryPath", false));
result.addAll(createPathList(properties, "DelphiTranslatedLibraryPath", false));

return Collections.unmodifiableList(allPaths);
return Collections.unmodifiableList(result);
}

private List<Path> createDebugSourceDirectories(ProjectProperties properties) {
return createPathList(properties, "Debugger_DebugSourcePath");
private List<Path> createBrowsingPathDirectories(ProjectProperties properties) {
return createPathList(properties, "DelphiBrowsingPath", false);
}

private List<Path> createPathList(ProjectProperties properties, String propertyName) {
Expand Down Expand Up @@ -176,6 +176,8 @@ private static class DelphiProjectImpl implements DelphiProject {
private List<Path> sourceFiles = Collections.emptyList();
private List<Path> searchDirectories = Collections.emptyList();
private List<Path> debugSourceDirectories = Collections.emptyList();
private List<Path> libraryPathDirectories = Collections.emptyList();
private List<Path> browsingPathDirectories = Collections.emptyList();
private Map<String, String> unitAliases = Collections.emptyMap();

private void setDefinitions(Set<String> definitions) {
Expand All @@ -199,6 +201,14 @@ private void setDebugSourceDirectories(List<Path> debugSourceDirectories) {
this.debugSourceDirectories = List.copyOf(debugSourceDirectories);
}

private void setLibraryPath(List<Path> libraryPathDirectories) {
this.libraryPathDirectories = List.copyOf(libraryPathDirectories);
}

private void setBrowsingPath(List<Path> browsingPathDirectories) {
this.browsingPathDirectories = List.copyOf(browsingPathDirectories);
}

private void setUnitAliases(Map<String, String> unitAliases) {
this.unitAliases = ImmutableSortedMap.copyOf(unitAliases, String.CASE_INSENSITIVE_ORDER);
}
Expand Down Expand Up @@ -228,6 +238,16 @@ public List<Path> getDebugSourceDirectories() {
return debugSourceDirectories;
}

@Override
public List<Path> getLibraryPathDirectories() {
return libraryPathDirectories;
}

@Override
public List<Path> getBrowsingPathDirectories() {
return browsingPathDirectories;
}

@Override
public Map<String, String> getUnitAliases() {
return unitAliases;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ private static boolean isPasFile(Path path) {
}

private void createUnitData(Path unitPath, boolean isSourceFile) {
if (unitPaths.add(unitPath) || isSourceFile) {
if (unitPaths.add(unitPath)) {
String unitName = FilenameUtils.getBaseName(unitPath.toString());
UnitData unitData = new UnitData(unitPath, isSourceFile);

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

processStandardLibrarySearchPaths();
searchPath.getRootDirectories().forEach(this::processSearchPath);
referencedFiles.forEach(file -> this.createUnitData(file, false));
sourceFiles.forEach(file -> this.createUnitData(file, true));
referencedFiles.forEach(file -> this.createUnitData(file, false));
searchPath.getRootDirectories().forEach(this::processSearchPath);

processStandardLibrarySearchPaths();

ProgressReport progressReport =
new ProgressReport(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ class DelphiProjectParserTest {
private static final String LIBRARY_PATH_PROJECT =
"/au/com/integradev/delphi/msbuild/LibraryPath.dproj";

private static final String BROWSING_PATH_PROJECT =
"/au/com/integradev/delphi/msbuild/BrowsingPath.dproj";

private EnvironmentVariableProvider environmentVariableProvider;
private Path environmentProj;

Expand Down Expand Up @@ -158,14 +161,20 @@ void testBadSourceFileProjectShouldContainValidSourceFiles() {
}

@Test
void testLibraryPathShouldBeAppendedToSearchDirectories() {
void testLibraryPathProject() {
DelphiProject project = parse(LIBRARY_PATH_PROJECT);

assertThat(project.getSearchDirectories())
assertThat(project.getLibraryPathDirectories())
.containsExactly(
DelphiUtils.getResource("/au/com/integradev/delphi/msbuild").toPath(),
DelphiUtils.getResource("/au/com/integradev/delphi").toPath(),
DelphiUtils.getResource("/au/com/integradev").toPath(),
DelphiUtils.getResource("/au/com").toPath());
DelphiUtils.getResource("/au/com/integradev").toPath());
}

@Test
void testBrowsingPathProject() {
DelphiProject project = parse(BROWSING_PATH_PROJECT);

assertThat(project.getBrowsingPathDirectories())
.containsExactly(DelphiUtils.getResource("/au/com/integradev/delphi").toPath());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import java.nio.file.spi.FileSystemProvider;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
Expand Down Expand Up @@ -157,6 +159,95 @@ void testStandardLibrarySearchPathShouldExcludeToolsUnits(
assertThat(symbolTable.getUnitByPath(excludedPath.toString())).isNull();
}

@Test
void testSonarSourcesArePrioritizedOverReferencedFiles(
@TempDir Path standardLibraryPath,
@TempDir Path referencedFilesPath,
@TempDir Path sourceFilesPath)
throws IOException {
createStandardLibrary(standardLibraryPath);
createStandardLibrary(referencedFilesPath);
createStandardLibrary(sourceFilesPath);

List<Path> referencedFiles;
try (Stream<Path> referencedFilesStream = Files.list(referencedFilesPath)) {
referencedFiles = referencedFilesStream.collect(Collectors.toUnmodifiableList());
}

List<Path> sourceFiles;
try (Stream<Path> sourceFilesStream = Files.list(sourceFilesPath)) {
sourceFiles = sourceFilesStream.collect(Collectors.toUnmodifiableList());
}

SymbolTable symbolTable =
SymbolTable.builder()
.preprocessorFactory(new DelphiPreprocessorFactory(Platform.WINDOWS))
.typeFactory(TypeFactoryUtils.defaultFactory())
.standardLibraryPath(standardLibraryPath)
.referencedFiles(referencedFiles)
.sourceFiles(sourceFiles)
.build();

assertThat(symbolTable.getUnitByPath(standardLibraryPath.resolve("SysInit.pas").toString()))
.isNull();
assertThat(symbolTable.getUnitByPath(referencedFilesPath.resolve("SysInit.pas").toString()))
.isNull();
assertThat(symbolTable.getUnitByPath(sourceFilesPath.resolve("SysInit.pas").toString()))
.isNotNull();
}

@Test
void testReferencedFilesArePrioritizedOverSearchPath(
@TempDir Path standardLibraryPath,
@TempDir Path searchPathRoot,
@TempDir Path referencedFilesPath)
throws IOException {
createStandardLibrary(standardLibraryPath);
createStandardLibrary(searchPathRoot);
createStandardLibrary(referencedFilesPath);

List<Path> referencedFiles;
try (Stream<Path> referencedFilesStream = Files.list(referencedFilesPath)) {
referencedFiles = referencedFilesStream.collect(Collectors.toUnmodifiableList());
}

SymbolTable symbolTable =
SymbolTable.builder()
.preprocessorFactory(new DelphiPreprocessorFactory(Platform.WINDOWS))
.typeFactory(TypeFactoryUtils.defaultFactory())
.standardLibraryPath(standardLibraryPath)
.searchPath(SearchPath.create(List.of(searchPathRoot)))
.referencedFiles(referencedFiles)
.build();

assertThat(symbolTable.getUnitByPath(standardLibraryPath.resolve("SysInit.pas").toString()))
.isNull();
assertThat(symbolTable.getUnitByPath(searchPathRoot.resolve("SysInit.pas").toString()))
.isNull();
assertThat(symbolTable.getUnitByPath(referencedFilesPath.resolve("SysInit.pas").toString()))
.isNotNull();
}

@Test
void testSearchPathIsPrioritizedOverStandardLibrary(
@TempDir Path standardLibraryPath, @TempDir Path searchPathRoot) throws IOException {
createStandardLibrary(standardLibraryPath);
createStandardLibrary(searchPathRoot);

SymbolTable symbolTable =
SymbolTable.builder()
.preprocessorFactory(new DelphiPreprocessorFactory(Platform.WINDOWS))
.typeFactory(TypeFactoryUtils.defaultFactory())
.standardLibraryPath(standardLibraryPath)
.searchPath(SearchPath.create(List.of(searchPathRoot)))
.build();

assertThat(symbolTable.getUnitByPath(standardLibraryPath.resolve("SysInit.pas").toString()))
.isNull();
assertThat(symbolTable.getUnitByPath(searchPathRoot.resolve("SysInit.pas").toString()))
.isNotNull();
}

@ParameterizedTest
@ValueSource(strings = {"#$@", "unit ErrorUnit;"})
void testRecognitionErrorInImportShouldNotThrow(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DelphiBrowsingPath>../</DelphiBrowsingPath>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DelphiLibraryPath>../../</DelphiLibraryPath>
<DelphiTranslatedLibraryPath>../../../</DelphiTranslatedLibraryPath>
<DCC_UnitSearchPath>../</DCC_UnitSearchPath>
<DelphiLibraryPath>../</DelphiLibraryPath>
<DelphiTranslatedLibraryPath>../../</DelphiTranslatedLibraryPath>
</PropertyGroup>
</Project>
Loading
Loading