blob: 407fef38490f63af25ca568eef7ac8378c13ff37 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2021 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.r.core.model;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.statet.jcommons.collections.ImCollections;
import org.eclipse.statet.jcommons.lang.NonNullByDefault;
import org.eclipse.statet.jcommons.lang.Nullable;
import org.eclipse.statet.internal.r.core.FilteredFrame;
import org.eclipse.statet.internal.r.core.RCorePlugin;
import org.eclipse.statet.internal.r.core.RProjectNature;
import org.eclipse.statet.internal.r.core.sourcemodel.RModelManagerImpl;
import org.eclipse.statet.ltk.model.core.element.SourceElement;
import org.eclipse.statet.ltk.model.core.element.SourceUnitModelInfo;
import org.eclipse.statet.ltk.model.core.element.WorkspaceSourceUnit;
import org.eclipse.statet.r.core.RProject;
import org.eclipse.statet.r.core.RProjects;
import org.eclipse.statet.r.core.rsource.ast.RAstNode;
/**
* R LTK model
*/
@NonNullByDefault
public final class RModel {
public static final String R_TYPE_ID= "R"; //$NON-NLS-1$
public static final RElementName GLOBAL_ENV_NAME= RElementName.create(RElementName.SCOPE_SEARCH_ENV, ".GlobalEnv"); //$NON-NLS-1$
public static final String BUILDPATH_PROBLEM_MARKER= "org.eclipse.statet.r.resourceMarkers.BuildpathProblem"; //$NON-NLS-1$
public static final String R_MODEL_PROBLEM_MARKER= "org.eclipse.statet.r.resourceMarkers.RModelProblem"; //$NON-NLS-1$
/**
* @return the manager for the R model
*/
public static RModelManager getRModelManager() {
return RCorePlugin.getInstance().getRModelManager();
}
public static @Nullable RSourceUnitModelInfo getRModelInfo(final @Nullable SourceUnitModelInfo modelInfo) {
if (modelInfo != null) {
if (modelInfo instanceof RSourceUnitModelInfo) {
return (RSourceUnitModelInfo)modelInfo;
}
for (final Object aAttachment : modelInfo.getAttachments()) {
if (aAttachment instanceof RSourceUnitModelInfo) {
return (RSourceUnitModelInfo)aAttachment;
}
}
}
return null;
}
public static @Nullable RSourceFrame searchFrame(@Nullable RAstNode node) {
while (node != null) {
final List<Object> attachments= node.getAttachments();
for (final Object attachment : attachments) {
if (attachment instanceof RSourceFrame) {
return (RSourceFrame)attachment;
}
}
node= node.getRParent();
}
return null;
}
private static @Nullable String checkValidPkgFrame(final RFrame frame) {
final RElementName elementName;
return (frame.getFrameType() == RFrame.PACKAGE
&& (elementName= frame.getElementName()) != null) ?
elementName.getSegmentName() :
null;
}
private static boolean isValidFrame(final RFrame frame, final @Nullable String pkgName) {
final String name;
return (pkgName == null
|| ((name= checkValidPkgFrame(frame)) != null
&& name.equals(pkgName) ));
}
private static boolean isValidFrame(final RFrame frame, final @Nullable Set<String> pkgNames) {
final String name;
return (pkgNames == null
|| ((name= checkValidPkgFrame(frame)) != null
&& pkgNames.contains(name) ));
}
public static List<RFrame> createDirectFrameList(final RFrame frame,
final @Nullable RElementName expliciteScope) {
final ArrayList<RFrame> list= new ArrayList<>();
final String pkgName= (expliciteScope != null && RElementName.isPackageFacetScopeType(expliciteScope.getType())) ?
expliciteScope.getSegmentName() : null;
int idx= 0;
if (isValidFrame(frame, pkgName)) {
list.add(frame);
}
while (idx < list.size()) {
final List<? extends RFrame> ps= list.get(idx++).getPotentialParents();
for (final RFrame parent : ps) {
if (isValidFrame(parent, pkgName) && !list.contains(parent)) {
list.add(parent);
}
}
}
return list;
}
public static List<RFrame> createDirectFrameList(final RFrame frame) {
return createDirectFrameList(frame, null);
}
public static Set<String> createImportedPackageList(final RSourceUnitModelInfo modelInfo) {
final Set<String> importedPackages= new HashSet<>();
importedPackages.add("base"); //$NON-NLS-1$
if (modelInfo != null) {
final PackageReferences packages= modelInfo.getReferencedPackages();
for (final String name : packages.getAllPackageNames()) {
if (packages.isImported(name)) {
importedPackages.add(name);
}
}
}
return importedPackages;
}
public static List<RFrame> createProjectFrameList(@Nullable RProject project1,
final RSourceUnit scope,
final boolean pkgImports, final boolean projectDependencies,
@Nullable Set<String> importedPackages, @Nullable Set<String> pkgNames)
throws CoreException {
final ArrayList<RFrame> list= new ArrayList<>();
final RModelManager manager= getRModelManager();
if (project1 == null && scope instanceof WorkspaceSourceUnit) {
if (pkgImports && importedPackages == null) {
importedPackages= createImportedPackageList(
(RSourceUnitModelInfo)scope.getModelInfo(R_TYPE_ID, RModelManagerImpl.MODEL_FILE, null ));
}
project1= RProjects.getRProject(((WorkspaceSourceUnit)scope).getResource().getProject());
}
if (pkgImports && importedPackages == null) {
importedPackages= ImCollections.emptySet();
}
if (pkgNames == null) {
pkgNames= new HashSet<>();
}
if (project1 != null) {
{ final RFrame frame= manager.getProjectFrame(project1);
if (frame != null) {
if (projectDependencies || (pkgImports && isValidFrame(frame, importedPackages))) {
final String name;
if ((name= checkValidPkgFrame(frame)) != null) {
pkgNames.add(name);
}
list.add(new FilteredFrame(frame, scope));
}
}
}
final List<RProject> projects= new ArrayList<>();
try {
final IProject[] referencedProjects= project1.getProject().getReferencedProjects();
for (final IProject referencedProject : referencedProjects) {
final RProject rProject= RProjectNature.getRProject(referencedProject);
if (rProject != null) {
projects.add(rProject);
}
}
} catch (final CoreException e) {}
for (int i= 0; i < projects.size(); i++) {
final RProject project= projects.get(i);
final RFrame frame= manager.getProjectFrame(project);
if (frame != null) {
if (projectDependencies || (pkgImports && isValidFrame(frame, importedPackages))) {
final String name;
if ((name= checkValidPkgFrame(frame)) != null) {
pkgNames.add(name);
}
list.add(frame);
}
}
try {
final IProject[] referencedProjects= project.getProject().getReferencedProjects();
for (final IProject referencedProject : referencedProjects) {
final RProject rProject= RProjectNature.getRProject(referencedProject);
if (rProject != null && !projects.contains(rProject)) {
projects.add(rProject);
}
}
} catch (final CoreException e) {}
}
}
if (pkgImports && importedPackages != null) {
for (final String pkgName : importedPackages) {
if (!pkgNames.contains(pkgName)) {
final RFrame frame= manager.getPkgProjectFrame(pkgName);
if (frame != null) {
list.add(frame);
}
}
}
}
return list;
}
public static List<RFrame> createProjectFrameList(final @Nullable RProject project1,
final RSourceUnit scope) throws CoreException {
return createProjectFrameList(project1, scope, true, true, null, null);
}
public static List<SourceElement> searchDeclaration(final RElementAccess access,
final RSourceUnit su) throws CoreException {
assert (access != null);
final List<SourceElement> list= new ArrayList<>();
if (access.getSegmentName() == null) {
return list;
}
final RFrame suFrame= access.getFrame();
final List<RFrame> directFrames= createDirectFrameList(suFrame);
for (final RFrame frame : directFrames) {
if (checkFrame(frame, access, list)) {
return list;
}
}
final List<RFrame> projectFrames= createProjectFrameList(null, su);
for (final RFrame frame : projectFrames) {
if (checkFrame(frame, access, list)) {
return list;
}
}
return list;
}
private static boolean checkFrame(final RFrame frame, final RElementAccess access, final List<SourceElement> list) {
final List<? extends RElement> elements= frame.getModelChildren(null);
for (final RElement element : elements) {
final RElementName name= element.getElementName();
if (name != null
&& access.getType() == name.getType()
&& Objects.equals(access.getSegmentName(), name.getSegmentName())
&& element instanceof SourceElement) {
list.add((SourceElement)element);
}
}
if (!list.isEmpty()) {
final SourceElement first= list.get(0);
switch (first.getElementType() & RElement.MASK_C2) {
case RElement.R_S4METHOD:
case RElement.R_GENERAL_VARIABLE:
return false;
default:
return true;
}
}
return false;
}
public static @Nullable RElementName getFQElementName(final @Nullable RElement var) {
final List<RElementName> segments= getFQFullName(var, 0);
return (segments != null) ? RElementName.create(segments) : null;
}
private static @Nullable List<RElementName> getFQFullName(final @Nullable RElement var, int count) {
if (var != null) {
final RElementName elementName= var.getElementName();
if (elementName != null) {
{ RElementName segment= elementName;
do {
count++;
segment= segment.getNextSegment();
} while (segment != null);
}
List<RElementName> segments;
final RElementName scope= elementName.getScope();
if (scope != null) {
if (RElementName.isScopeType(scope.getType())) {
segments= new ArrayList<>(count + 1);
segments.add(scope);
}
else {
segments= getFQFullName(var.getModelParent(), count);
}
}
else {
if (RElementName.isScopeType(elementName.getType())) {
segments= new ArrayList<>(count);
}
else {
segments= getFQFullName(var.getModelParent(), count);
}
}
if (segments != null) {
RElementName segment= elementName;
do {
segments.add(segment);
segment= segment.getNextSegment();
} while (segment != null);
return segments;
}
}
}
return null;
}
private RModel() {}
}