ThemisXAnalysisSolverFile.java
/*
* Themis: Java Project Framework
* Copyright 2012-2026. Tony Washer
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package io.github.tonywasher.joceanus.themis.xanalysis.solver.proj;
import io.github.tonywasher.joceanus.themis.xanalysis.parser.base.ThemisXAnalysisInstance.ThemisXAnalysisClassInstance;
import io.github.tonywasher.joceanus.themis.xanalysis.parser.proj.ThemisXAnalysisFile;
import io.github.tonywasher.joceanus.themis.xanalysis.solver.proj.ThemisXAnalysisSolverDef.ThemisXAnalysisSolverFileDef;
import io.github.tonywasher.joceanus.themis.xanalysis.solver.proj.ThemisXAnalysisSolverDef.ThemisXAnalysisSolverPackageDef;
import java.util.ArrayList;
import java.util.List;
/**
* Solver File.
*/
public class ThemisXAnalysisSolverFile
implements ThemisXAnalysisSolverFileDef {
/**
* The owning package.
*/
private final ThemisXAnalysisSolverPackageDef thePackage;
/**
* The underlying file.
*/
private final ThemisXAnalysisFile theFile;
/**
* The top-level class.
*/
private final ThemisXAnalysisSolverClass theTopLevel;
/**
* The classes.
*/
private final List<ThemisXAnalysisSolverClass> theClasses;
/**
* The referenced classes.
*/
private final List<ThemisXAnalysisSolverClass> theReferenced;
/**
* Is the reference list circular?
*/
private boolean isCircular;
/**
* Constructor.
*
* @param pPackage the owning package
* @param pFile the parsed file
*/
ThemisXAnalysisSolverFile(final ThemisXAnalysisSolverPackageDef pPackage,
final ThemisXAnalysisFile pFile) {
/* Store the parameters */
thePackage = pPackage;
theFile = pFile;
/* Populate the classList */
theClasses = new ArrayList<>();
for (ThemisXAnalysisClassInstance myClass : theFile.getClasses()) {
final ThemisXAnalysisSolverClass mySolverClass = new ThemisXAnalysisSolverClass(this, myClass);
theClasses.add(mySolverClass);
}
/* Determine top-level class */
theTopLevel = theClasses.stream().filter(ThemisXAnalysisSolverClass::isTopLevel).findFirst().orElse(null);
/* Create the referenced classes */
theReferenced = new ArrayList<>();
}
@Override
public ThemisXAnalysisSolverPackageDef getOwningPackage() {
return thePackage;
}
@Override
public ThemisXAnalysisFile getUnderlyingFile() {
return theFile;
}
/**
* Obtain the top-level class.
*
* @return the top-level
*/
public ThemisXAnalysisSolverClass getTopLevel() {
return theTopLevel;
}
/**
* Obtain the classes.
*
* @return the classes
*/
public List<ThemisXAnalysisSolverClass> getClasses() {
return theClasses;
}
/**
* Is the reference list circular?
*
* @return true/false
*/
public boolean isCircular() {
return isCircular;
}
@Override
public String toString() {
return theFile.toString();
}
/**
* Obtain the list of classes that reference the named package.
*
* @param pPackage the package
* @return the list of referencing classes
*/
public List<ThemisXAnalysisSolverClass> getReferencesTo(final String pPackage) {
/* Loop through the classes */
final List<ThemisXAnalysisSolverClass> myReferences = new ArrayList<>();
for (ThemisXAnalysisSolverClass myReference : theReferenced) {
if (pPackage.equals(myReference.getPackageName())) {
myReferences.add(myReference);
}
}
return myReferences;
}
/**
* Obtain the list of local classes that are referenced.
*
* @return the list of referencing classes
*/
private List<ThemisXAnalysisSolverClass> getLocalReferences() {
return getReferencesTo(thePackage.toString());
}
/**
* Set the referenced classes.
*
* @param pReferenced the referenced classes
*/
public void setReferenced(final List<ThemisXAnalysisSolverClass> pReferenced) {
/* Add all references except for a self-reference */
theReferenced.addAll(pReferenced.stream().filter(s -> !s.equals(getTopLevel())).toList());
}
/**
* process local references.
*/
public void processLocalReferences() {
/* Create a reference list */
final List<ThemisXAnalysisSolverClass> myFullyReferenced = new ArrayList<>();
/* Loop through the referenced local classes */
for (ThemisXAnalysisSolverClass myClass : getLocalReferences()) {
/* Process the class */
processLocalReferences(myFullyReferenced, myClass);
}
/* Determine whether we are circular */
isCircular = myFullyReferenced.contains(theTopLevel);
}
/**
* process local references.
*
* @param pReferences the references list
* @param pClass the class to process local references for
*/
private void processLocalReferences(final List<ThemisXAnalysisSolverClass> pReferences,
final ThemisXAnalysisSolverClass pClass) {
/* If this is not already in the local reference list */
if (!pReferences.contains(pClass)) {
/* Add the class */
pReferences.add(pClass);
/* Only process further if we have not found circularity */
if (!pClass.equals(theTopLevel)) {
/* Loop through the local references */
for (ThemisXAnalysisSolverClass myClass : ((ThemisXAnalysisSolverFile) pClass.getOwningFile()).getLocalReferences()) {
/* Process the local references */
processLocalReferences(pReferences, myClass);
}
}
}
}
}