Skip to content
Open
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
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ platformVersion = 2024.2.4
# Example: platformPlugins = com.jetbrains.php:203.4449.22, org.intellij.scala:2023.3.27@EAP
platformPlugins =
# Example: platformBundledPlugins = com.intellij.java
platformBundledPlugins =
platformBundledPlugins = com.intellij.java

# Gradle Releases -> https://github.com/gradle/gradle/releases
gradleVersion = 8.11
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@

import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.util.Query;
import org.jetbrains.annotations.NotNull;
Expand Down Expand Up @@ -97,6 +100,35 @@ public static FeatureFileMapping getFeatureFileMapping(Project project, FeatureM
return featureFileMapping;
}
// &end[FeatureFileMapping]
public static FeatureFileMapping getFeatureFileMappingFile(Project project, FeatureModelFeature feature) {
FeatureFileMapping featureFileMapping = new FeatureFileMapping(feature);
FileType fileTypeFeatureFile = FileTypeManager.getInstance().getFileTypeByExtension("feature-to-file");
System.out.println("Querying");
GlobalSearchScope globalSearchScope = GlobalSearchScope.getScopeRestrictedByFileTypes(GlobalSearchScope.projectScope(project), fileTypeFeatureFile);
Query<PsiReference> featureReference = ReferencesSearch.search(feature, globalSearchScope, true);

for (PsiReference reference : ReadAction.compute(() -> featureReference)) {
System.out.println("Querying loop");
//get comment sibling of the feature comment

PsiElement element = reference.getElement();
var originatingFilePath = ReadAction.compute(()->element.getContainingFile().getVirtualFile().getPath());
//determine file type and process content
var fileType = ReadAction.compute(element::getContainingFile);
if (fileType instanceof CodeAnnotationFile) {
processCodeFile(project, featureFileMapping, element, originatingFilePath);
} else if (fileType instanceof FileAnnotationFile) {
processFeatureToFile(project, featureFileMapping, element, originatingFilePath);
} else if (fileType instanceof FolderAnnotationFile) {
PsiDirectory dir = ReadAction.compute(fileType::getContainingDirectory);
if (dir == null)
continue;
processFeatureToFolder(project, featureFileMapping, dir, originatingFilePath);
}
}
featureFileMapping.buildFromQueue();
return featureFileMapping;
}

private static void processCodeFile(Project project, FeatureFileMapping featureFileMapping, PsiElement element, String originatingFilePath) {
var commentElement = ReadAction.compute(() -> PsiTreeUtil.getContextOfType(element, PsiComment.class));
Expand Down
144 changes: 127 additions & 17 deletions src/main/java/se/isselab/HAnS/referencing/FeatureReference.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,44 @@

import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiElementResolveResult;
import com.intellij.psi.PsiReferenceBase;
import com.intellij.psi.ResolveResult;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import se.isselab.HAnS.AnnotationIcons;
import se.isselab.HAnS.codeAnnotation.psi.CodeAnnotationLpq;
import se.isselab.HAnS.codeAnnotation.psi.impl.CodeAnnotationPsiImplUtil;
import se.isselab.HAnS.featureLocation.FeatureFileMapping;
import se.isselab.HAnS.featureLocation.FeatureLocation;
import se.isselab.HAnS.featureLocation.FeatureLocationManager;
import se.isselab.HAnS.featureModel.FeatureModelUtil;
import se.isselab.HAnS.featureModel.psi.FeatureModelFeature;
import se.isselab.HAnS.fileAnnotation.psi.FileAnnotationLpq;
import se.isselab.HAnS.fileAnnotation.psi.impl.FileAnnotationPsiImplUtil;
import se.isselab.HAnS.folderAnnotation.psi.FolderAnnotationLpq;
import se.isselab.HAnS.folderAnnotation.psi.impl.FolderAnnotationPsiImplUtil;
import se.isselab.HAnS.pluginExtensions.ProjectMetricsService;
import se.isselab.HAnS.pluginExtensions.backgroundTasks.featureFileMappingTasks.FeatureFileMappingCallback;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class FeatureReference extends PsiReferenceBase<PsiElement> {
public class FeatureReference extends PsiPolyVariantReferenceBase<PsiElement> {

private final String lpq;
private PsiElement element;

public FeatureReference(@NotNull PsiElement element, TextRange textRange) {
super(element, textRange);
this.element = element;
lpq = element.getText().substring(textRange.getStartOffset(), textRange.getEndOffset());
}

Expand Down Expand Up @@ -71,17 +82,6 @@ else if (myElement instanceof CodeAnnotationLpq) {
return myElement;
}

@Nullable
@Override
public PsiElement resolve() {
Project project = myElement.getProject();
final List<FeatureModelFeature> features = FeatureModelUtil.findLPQ(project, lpq);
List<ResolveResult> results = new ArrayList<>();
for (FeatureModelFeature feature : features) {
results.add(new PsiElementResolveResult(feature));
}
return results.size() == 1 ? results.get(0).getElement() : null;
}

@Override
public Object @NotNull [] getVariants() {
Expand All @@ -99,4 +99,114 @@ public PsiElement resolve() {
return variants.toArray();
}

}
private boolean isEndTag(PsiElement psiElement) {
if (psiElement.getText().startsWith("&end")) return true;
if (psiElement.getParent() != null) {
return isEndTag(psiElement.getParent());
}
return false;
}

@Override
public ResolveResult @NotNull [] multiResolve(boolean b) {
Project project = element.getProject();

List<ResolveResult> results = new ArrayList<>();

if(element instanceof FileAnnotationLpq) {
//System.out.println("FileLpq");
ProjectMetricsService projectMetricsService = new ProjectMetricsService(project);
final List<FeatureModelFeature> features = FeatureModelUtil.findLPQ(project, lpq);
if (features.isEmpty()) {
System.out.println("no feature found");
return results.toArray(new ResolveResult[0]);
}
FeatureModelFeature feature = features.get(0);
System.out.println("Querying");
FeatureFileMapping featureFileMapping = FeatureLocationManager.getFeatureFileMappingFile(project, feature);
ArrayList<FeatureLocation> featureLocations = featureFileMapping.getFeatureLocations();
System.out.println("Amount of locations: " + featureLocations.size());
for (FeatureLocation featureLocation : featureLocations) {
System.out.println(featureLocation.toString());
}
//CompletableFuture<FeatureFileMapping> future = new CompletableFuture<>();
/*projectMetricsService.getFeatureFileMappingBackground(feature, new FeatureFileMappingCallback() {
@Override
public void onComplete(FeatureFileMapping featureFileMapping) {
future.complete(featureFileMapping);
}
});
try {
/* Waiting for this takes to long, but we also do not know how to get it once and save
* it for later, as the FeatureReference object is newly constructed everytime
FeatureFileMapping featureFileMapping = future.get();

} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}*/
} else if(element instanceof CodeAnnotationLpq) {
if (isEndTag(element)) return ResolveResult.EMPTY_ARRAY;
final List<FeatureModelFeature> features = FeatureModelUtil.findLPQ(project, lpq);

for (FeatureModelFeature feature : features) {

PsiElement commentElement = ReadAction.compute(() -> PsiTreeUtil.getContextOfType(element, PsiComment.class));

if(commentElement == null) continue;

PsiFile file = commentElement.getContainingFile();
String[] lines = file.getText().split("\n");

int beginLineNumber = getLine(project, commentElement);
int endLineNumber = 1;

for(String line : lines) {
if(endLineNumber > beginLineNumber && line.contains("&end[" + feature.getName() + "]")){
break;
}
endLineNumber++;
}


results.add(new PsiElementResolveResult(feature));
}
}
return results.toArray(new ResolveResult[0]);
}
public ArrayList<String> getAllFileNamesForFeature(String[] lines, String featureName) {
String[] nonEmptyLines = Arrays.stream(lines).filter((String line) -> !line.trim().isBlank()).toArray(String[]::new);
ArrayList<String> fileNames = new ArrayList<>();
for (int i = 0; i + 1 < nonEmptyLines.length; i+=2) {
String[] features = nonEmptyLines[i + 1].split(",");
boolean featureNameFound = false;
for (String feature : features) {
if (feature.trim().equals(featureName)){
featureNameFound = true;
break;
}
}
if (!featureNameFound) continue;
fileNames.addAll(Arrays.stream(nonEmptyLines[i].split(",")).map(String::trim).toList());
}

return fileNames;
}

private int getLine(Project project, PsiElement elem) {

PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(project);
PsiFile openedFile = ReadAction.compute(elem::getContainingFile);

//iterate over each psiElement and check for PsiComment-Feature-Annotations
if (openedFile == null)
return -1;
Document document = psiDocumentManager.getDocument(openedFile);
if (document == null)
return -1;

return document.getLineNumber(elem.getTextRange().getStartOffset());
}
}

1 change: 1 addition & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ limitations under the License.
<!-- please see https://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
on how to target different products -->
<depends>com.intellij.modules.platform</depends>
<depends>com.intellij.modules.java</depends>

<extensions defaultExtensionNs="com.intellij">
<!-- &begin[HAnS::FeatureModel] -->
Expand Down