blob: efd8079d1061f92342ad0403c4119a4719264b91 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2008, 2020 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.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.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.RModelManager;
import org.eclipse.statet.ltk.model.core.elements.ISourceElement;
import org.eclipse.statet.ltk.model.core.elements.ISourceUnitModelInfo;
import org.eclipse.statet.ltk.model.core.elements.IWorkspaceSourceUnit;
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
*/
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 IRModelManager getRModelManager() {
return RCorePlugin.getInstance().getRModelManager();
}
public static IRModelInfo getRModelInfo(final ISourceUnitModelInfo modelInfo) {
if (modelInfo != null) {
if (modelInfo instanceof IRModelInfo) {
return (IRModelInfo) modelInfo;
}
for (final Object aAttachment : modelInfo.getAttachments()) {
if (aAttachment instanceof IRModelInfo) {
return (IRModelInfo) aAttachment;
}
}
}
return null;
}
public static IRFrameInSource searchFrame(RAstNode node) {
while (node != null) {
final List<Object> attachments= node.getAttachments();
for (final Object attachment : attachments) {
if (attachment instanceof IRFrameInSource) {
return (IRFrameInSource) attachment;
}
}
node= node.getRParent();
}
return null;
}
private static boolean isValidPkgFrame(final IRFrame frame) {
return (frame.getFrameType() == IRFrame.PACKAGE
&& frame.getElementName().getSegmentName() != null );
}
private static boolean isValidFrame(final IRFrame frame, final String pkgName) {
return (pkgName == null
|| (isValidPkgFrame(frame)
&& frame.getElementName().getSegmentName().equals(pkgName) ));
}
private static boolean isValidFrame(final IRFrame frame, final Set<String> pkgNames) {
return (pkgNames == null
|| (isValidPkgFrame(frame)
&& pkgNames.contains(frame.getElementName().getSegmentName()) ));
}
public static List<IRFrame> createDirectFrameList(final IRFrame frame,
final RElementName expliciteScope) {
final ArrayList<IRFrame> 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 IRFrame> ps= list.get(idx++).getPotentialParents();
for (final IRFrame parent : ps) {
if (isValidFrame(parent, pkgName) && !list.contains(parent)) {
list.add(parent);
}
}
}
return list;
}
public static List<IRFrame> createDirectFrameList(final IRFrame frame) {
return createDirectFrameList(frame, null);
}
public static Set<String> createImportedPackageList(final IRModelInfo modelInfo) {
final Set<String> importedPackages= new HashSet<>();
importedPackages.add("base"); //$NON-NLS-1$
if (modelInfo != null) {
final IPackageReferences packages= modelInfo.getReferencedPackages();
for (final String name : packages.getAllPackageNames()) {
if (packages.isImported(name)) {
importedPackages.add(name);
}
}
}
return importedPackages;
}
public static List<IRFrame> createProjectFrameList(RProject project1,
final IRSourceUnit scope,
final boolean pkgImports, final boolean projectDependencies,
Set<String> importedPackages, Set<String> pkgNames)
throws CoreException {
final ArrayList<IRFrame> list= new ArrayList<>();
final IRModelManager manager= getRModelManager();
if (project1 == null && scope instanceof IWorkspaceSourceUnit) {
if (pkgImports && importedPackages == null) {
importedPackages= createImportedPackageList(
(IRModelInfo) scope.getModelInfo(R_TYPE_ID, RModelManager.MODEL_FILE, null ));
}
project1= RProjects.getRProject(((IWorkspaceSourceUnit) scope).getResource().getProject());
}
if (pkgImports && importedPackages == null) {
importedPackages= ImCollections.emptySet();
}
if (pkgNames == null) {
pkgNames= new HashSet<>();
}
if (project1 != null) {
{ final IRFrame frame= manager.getProjectFrame(project1);
if (frame != null) {
if (projectDependencies || (pkgImports && isValidFrame(frame, importedPackages))) {
if (isValidPkgFrame(frame)) {
pkgNames.add(frame.getElementName().getSegmentName());
}
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 IRFrame frame= manager.getProjectFrame(project);
if (frame != null) {
if (projectDependencies || (pkgImports && isValidFrame(frame, importedPackages))) {
if (isValidPkgFrame(frame)) {
pkgNames.add(frame.getElementName().getSegmentName());
}
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 IRFrame frame= manager.getPkgProjectFrame(pkgName);
if (frame != null) {
list.add(frame);
}
}
}
}
return list;
}
public static List<IRFrame> createProjectFrameList(final RProject project1,
final IRSourceUnit scope) throws CoreException {
return createProjectFrameList(project1, scope, true, true, null, null);
}
public static List<ISourceElement> searchDeclaration(final RElementAccess access,
final IRSourceUnit su) throws CoreException {
assert (access != null);
final List<ISourceElement> list= new ArrayList<>();
if (access.getSegmentName() == null) {
return list;
}
final IRFrame suFrame= access.getFrame();
final List<IRFrame> directFrames= RModel.createDirectFrameList(suFrame);
for (final IRFrame frame : directFrames) {
if (checkFrame(frame, access, list)) {
return list;
}
}
final List<IRFrame> projectFrames= RModel.createProjectFrameList(null, su);
for (final IRFrame frame : projectFrames) {
if (checkFrame(frame, access, list)) {
return list;
}
}
return list;
}
private static boolean checkFrame(final IRFrame frame, final RElementAccess access, final List<ISourceElement> list) {
final List<? extends IRElement> elements= frame.getModelChildren(null);
for (final IRElement element : elements) {
final RElementName name= element.getElementName();
if (name != null
&& access.getType() == name.getType()
&& access.getSegmentName().equals(name.getSegmentName())
&& element instanceof ISourceElement) {
list.add((ISourceElement) element);
}
}
if (!list.isEmpty()) {
final ISourceElement first= list.get(0);
switch (first.getElementType() & IRElement.MASK_C2) {
case IRElement.R_S4METHOD:
case IRElement.R_GENERAL_VARIABLE:
return false;
default:
return true;
}
}
return false;
}
public static @Nullable RElementName getFQElementName(final @Nullable IRElement var) {
final List<RElementName> segments= getFQFullName(var, 0);
return (segments != null) ? RElementName.create(segments) : null;
}
private static @Nullable List<RElementName> getFQFullName(final @Nullable IRElement 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() {}
}