| /******************************************************************************* |
| * Copyright (c) 2004, 2007 IBM Corporation and others. All rights reserved. This |
| * program and the accompanying materials are made available under the terms of |
| * the Eclipse Public License v1.0 which accompanies this distribution, and is |
| * available at http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: Sian January - initial version |
| * Matt Chapman - add source of advice markers |
| ******************************************************************************/ |
| package org.eclipse.ajdt.internal.ui.markers; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import org.aspectj.asm.IProgramElement; |
| import org.aspectj.asm.IRelationship; |
| import org.aspectj.weaver.AdviceKind; |
| import org.aspectj.weaver.model.AsmRelationshipProvider; |
| import org.eclipse.ajdt.core.AJLog; |
| import org.eclipse.ajdt.core.model.AJProjectModelFacade; |
| import org.eclipse.ajdt.core.model.AJProjectModelFactory; |
| import org.eclipse.ajdt.internal.ui.preferences.AspectJPreferences; |
| import org.eclipse.ajdt.internal.ui.text.UIMessages; |
| import org.eclipse.ajdt.ui.IAJModelMarker; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IPackageFragmentRoot; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| |
| /** |
| * Class responsible for advice and declaration markers. Updates the markers for |
| * a given project when it is built. |
| */ |
| public class UpdateAJMarkers { |
| |
| |
| private final AJProjectModelFacade model; |
| private final IProject project; |
| private final IFile[] sourceFiles; |
| private int fileCount; |
| private int markerCount; |
| |
| /** |
| * To update markers for the entire project |
| * |
| * @param project the poject that needs updating |
| */ |
| public UpdateAJMarkers(IProject project) { |
| this.model = AJProjectModelFactory.getInstance().getModelForProject(project); |
| this.project = project; |
| this.sourceFiles = null; |
| this.fileCount = 0; |
| this.markerCount = 0; |
| } |
| /** |
| * to update markers for the given files only. |
| * |
| * @param project the poject that needs updating |
| * |
| * @param sourceFiles List of Strings of absolute paths of files that |
| * need updating |
| * |
| * @deprecated Use {@link UpdateAJMarkers#UpdateAJMarkers(IProject, IFile[])} instead |
| */ |
| public UpdateAJMarkers(IProject project, File[] sourceFiles) { |
| this.model = AJProjectModelFactory.getInstance().getModelForProject(project); |
| this.project = project; |
| this.sourceFiles = DeleteAndUpdateAJMarkersJob.javaFileToIFile(sourceFiles, project); |
| } |
| |
| /** |
| * to update markers for the given files only. |
| * |
| * @param project the poject that needs updating |
| * |
| * @param sourceFiles List of Strings of absolute paths of files that |
| * need updating |
| * |
| */ |
| public UpdateAJMarkers(IProject project, IFile[] sourceFiles) { |
| this.model = AJProjectModelFactory.getInstance().getModelForProject(project); |
| this.project = project; |
| this.sourceFiles = sourceFiles; |
| } |
| |
| protected IStatus run(IProgressMonitor monitor) { |
| AJLog.logStart("Create markers: " + project.getName()); |
| if (sourceFiles != null) { |
| addMarkersForFiles(monitor); |
| } else { |
| addMarkersForProject(monitor); |
| } |
| AJLog.logEnd(AJLog.BUILDER, "Create markers: " + project.getName(), "Finished creating markers for " + project.getName()); |
| AJLog.log(AJLog.BUILDER, "Created " + markerCount + " markers in " + fileCount + " files"); |
| return Status.OK_STATUS; |
| } |
| |
| |
| /** |
| * creates new markers for an entire project |
| */ |
| private void addMarkersForProject(IProgressMonitor monitor) { |
| if (! model.hasModel()) { |
| return; |
| } |
| try { |
| IJavaProject jProject = JavaCore.create(project); |
| IPackageFragmentRoot[] fragRoots = jProject.getPackageFragmentRoots(); |
| SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, fragRoots.length); |
| subMonitor.beginTask("Add markers for " + project.getName(), fragRoots.length); |
| for (int i = 0; i < fragRoots.length; i++) { |
| if (fragRoots[i].getKind() == IPackageFragmentRoot.K_SOURCE) { |
| IJavaElement[] frags = fragRoots[i].getChildren(); |
| for (int j = 0; j < frags.length; j++) { |
| Set<String> completedCUNames = new HashSet<String>(frags.length, 1.0f); |
| IJavaElement[] cus = ((IPackageFragment) frags[j]).getChildren(); |
| for (int k = 0; k < cus.length; k++) { |
| // ignore any class files in the source folder (Bug 258698) |
| if (cus[k].getElementType() == IJavaElement.COMPILATION_UNIT) { |
| // ignore duplicate compilation units |
| IResource resource = cus[k].getResource(); |
| if (!completedCUNames.contains(resource.getName())) { |
| subMonitor.subTask("Add markers for " + cus[k].getElementName()); |
| addMarkersForFile((ICompilationUnit) cus[k], ((ICompilationUnit) cus[k]).getResource()); |
| completedCUNames.add(resource.getName()); |
| fileCount++; |
| } |
| if (subMonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| } |
| } |
| } |
| subMonitor.worked(1); |
| } |
| } |
| } catch (JavaModelException e) { |
| } |
| |
| } |
| |
| |
| private void addMarkersForFiles(IProgressMonitor monitor) { |
| SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, sourceFiles.length); |
| for (int i = 0; i < sourceFiles.length; i++) { |
| IJavaElement unit = JavaCore.create(sourceFiles[i]); |
| if (unit != null && unit.exists() && unit instanceof ICompilationUnit) { |
| subMonitor.subTask("Add markers for " + unit.getElementName()); |
| addMarkersForFile((ICompilationUnit) unit, sourceFiles[i]); |
| fileCount++; |
| } |
| if (subMonitor.isCanceled()) { |
| throw new OperationCanceledException(); |
| } |
| subMonitor.worked(1); |
| } |
| } |
| |
| |
| |
| private void addMarkersForFile(ICompilationUnit cu, IResource resource) { |
| Map<Integer,List<IRelationship>> annotationMap = |
| model.getRelationshipsForFile(cu); |
| for (Entry<Integer,List<IRelationship>> entry : annotationMap.entrySet()) { |
| createMarker(resource, entry.getKey().intValue(), entry.getValue()); |
| markerCount++; |
| } |
| } |
| |
| private void createMarker(IResource resource, int lineNumber, List<IRelationship> relationships) { |
| String markerType = null; |
| boolean hasRuntime = false; |
| for (IRelationship relationship : relationships) { |
| hasRuntime |= relationship.hasRuntimeTest(); |
| String customMarkerType = getCustomMarker(relationship); |
| if (customMarkerType != null) { |
| // Create a marker of the saved type or don't create one. |
| // user has configured a custom marker |
| createCustomMarker(resource, customMarkerType, lineNumber, relationship); |
| |
| } else { |
| // must repeat for each target since |
| // each target may be of a different type |
| List<String> targets = relationship.getTargets(); |
| for (String target : targets) { |
| String markerTypeForRelationship = |
| getMarkerTypeForRelationship(relationship, target); |
| if (markerTypeForRelationship != null) { |
| if (markerType == null) { |
| markerType = markerTypeForRelationship; |
| } else if (!markerType.equals(markerTypeForRelationship)) { |
| markerType = getCombinedMarkerType(markerType, |
| markerTypeForRelationship, hasRuntime); |
| } |
| } |
| } |
| } |
| } // end for |
| |
| // Create the marker |
| if (markerType != null) { |
| try { |
| IMarker marker = resource.createMarker(markerType); |
| marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); |
| String label; |
| int numTargets = getNumTargets(relationships); |
| if (numTargets == 1) { |
| label = getMarkerLabel(relationships); |
| } else { |
| label = getMultipleMarkersLabel(numTargets); |
| } |
| marker.setAttribute(IMarker.MESSAGE, label); |
| marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_HIGH); |
| } catch (CoreException e) { |
| } |
| } |
| |
| } |
| |
| private int getNumTargets(List<IRelationship> relationships) { |
| int numTargets = 0; |
| for (IRelationship rel : relationships) { |
| for (String target : rel.getTargets()) { |
| if (!rel.getName().equals(AsmRelationshipProvider.MATCHES_DECLARE)) { |
| numTargets++; |
| } |
| } |
| } |
| return numTargets; |
| } |
| |
| private void createCustomMarker(IResource resource, String customMarkerType, |
| int lineNumber, IRelationship relationship) { |
| if (! customMarkerType.equals(AJMarkersDialog.NO_MARKERS)) { |
| try { |
| IMarker marker = resource |
| .createMarker(IAJModelMarker.CUSTOM_MARKER); |
| marker.setAttribute(IMarker.LINE_NUMBER, lineNumber); |
| String label; |
| label = getMarkerLabel(relationship); |
| marker.setAttribute(IMarker.MESSAGE, label); |
| marker.setAttribute(IMarker.PRIORITY, |
| IMarker.PRIORITY_HIGH); |
| marker.setAttribute( |
| CustomMarkerImageProvider.IMAGE_LOCATION_ATTRIBUTE, |
| customMarkerType); |
| } catch (CoreException e) { |
| } |
| } |
| } |
| |
| /** |
| * Get the marker type that should be used for the given relationship |
| * |
| * @param relationship |
| * @param target |
| * @return |
| */ |
| private String getMarkerTypeForRelationship(IRelationship relationship, String target) { |
| String name = relationship.getName(); |
| boolean runtimeTest = relationship.hasRuntimeTest(); |
| String markerType; |
| if (name.equals(AsmRelationshipProvider.ADVISED_BY)) { |
| IProgramElement advice = model.getProgramElement(target); |
| AdviceKind ak; |
| if (advice.getExtraInfo() != null) { |
| ak = AdviceKind.stringToKind(advice.getExtraInfo().getExtraAdviceInformation()); |
| } else { |
| ak = null; |
| } |
| if (runtimeTest) { |
| if (ak == null) { |
| markerType = IAJModelMarker.DYNAMIC_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Before) { |
| markerType = IAJModelMarker.DYNAMIC_BEFORE_ADVICE_MARKER; |
| } else if (ak == AdviceKind.After || |
| ak == AdviceKind.AfterReturning || |
| ak == AdviceKind.AfterThrowing) { |
| markerType = IAJModelMarker.DYNAMIC_AFTER_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Around) { |
| markerType = IAJModelMarker.DYNAMIC_AROUND_ADVICE_MARKER; |
| } else { |
| markerType = IAJModelMarker.DYNAMIC_ADVICE_MARKER; |
| } |
| } else { // no runtime test |
| if (ak == null) { |
| markerType = IAJModelMarker.ADVICE_MARKER; |
| } else if (ak == AdviceKind.Before) { |
| markerType = IAJModelMarker.BEFORE_ADVICE_MARKER; |
| } else if (ak == AdviceKind.After || |
| ak == AdviceKind.AfterReturning || |
| ak == AdviceKind.AfterThrowing) { |
| markerType = IAJModelMarker.AFTER_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Around) { |
| markerType = IAJModelMarker.AROUND_ADVICE_MARKER; |
| } else { |
| markerType = IAJModelMarker.ADVICE_MARKER; |
| } |
| } |
| } else if (name.equals(AsmRelationshipProvider.ADVISES)) { |
| IProgramElement advice = model.getProgramElement(relationship.getSourceHandle()); |
| AdviceKind ak; |
| if (advice.getExtraInfo() != null) { |
| ak = AdviceKind.stringToKind(advice.getExtraInfo().getExtraAdviceInformation()); |
| } else { |
| ak = null; |
| // hmmm...sometmes ExtradviceInformtion is null. |
| // try to get the advice kind by the name |
| if (advice.getName().startsWith("before")) { |
| ak = AdviceKind.Before; |
| } else if (advice.getName().startsWith("after")) { |
| ak = AdviceKind.After; |
| } else if (advice.getName().startsWith("around")) { |
| ak = AdviceKind.Around; |
| } |
| } |
| if (runtimeTest) { |
| if (ak == null) { |
| markerType = IAJModelMarker.SOURCE_DYNAMIC_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Before) { |
| markerType = IAJModelMarker.SOURCE_DYNAMIC_BEFORE_ADVICE_MARKER; |
| } else if (ak == AdviceKind.After || |
| ak == AdviceKind.AfterReturning || |
| ak == AdviceKind.AfterThrowing) { |
| markerType = IAJModelMarker.SOURCE_DYNAMIC_AFTER_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Around) { |
| markerType = IAJModelMarker.SOURCE_DYNAMIC_AROUND_ADVICE_MARKER; |
| } else { |
| markerType = IAJModelMarker.SOURCE_DYNAMIC_ADVICE_MARKER; |
| } |
| |
| } else { // no runtime test |
| if (ak == null) { |
| markerType = IAJModelMarker.SOURCE_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Before) { |
| markerType = IAJModelMarker.SOURCE_BEFORE_ADVICE_MARKER; |
| } else if (ak == AdviceKind.After || |
| ak == AdviceKind.AfterReturning || |
| ak == AdviceKind.AfterThrowing) { |
| markerType = IAJModelMarker.SOURCE_AFTER_ADVICE_MARKER; |
| } else if (ak == AdviceKind.Around) { |
| markerType = IAJModelMarker.SOURCE_AROUND_ADVICE_MARKER; |
| } else { |
| markerType = IAJModelMarker.SOURCE_ADVICE_MARKER; |
| } |
| } |
| } else if (name.equals(AsmRelationshipProvider.ANNOTATED_BY) || |
| name.equals(AsmRelationshipProvider.SOFTENED_BY) || |
| name.equals(AsmRelationshipProvider.INTER_TYPE_DECLARED_BY)) { |
| // note that we ignore MATCHES_DECLARE because that is taken care of |
| // by error and warning markers |
| markerType = IAJModelMarker.ITD_MARKER; |
| } else if (name.equals(AsmRelationshipProvider.ANNOTATES) || |
| name.equals(AsmRelationshipProvider.INTER_TYPE_DECLARES) || |
| name.equals(AsmRelationshipProvider.SOFTENS) || |
| name.equals(AsmRelationshipProvider.MATCHED_BY)) { |
| markerType = IAJModelMarker.SOURCE_ITD_MARKER; |
| |
| } else { |
| markerType = null; |
| } |
| return markerType; |
| } |
| |
| |
| private String getMultipleMarkersLabel(int number) { |
| return number + " " + UIMessages.AspectJMarkersAtLine; //$NON-NLS-1$ |
| } |
| |
| private String getMarkerLabel(List<IRelationship> relationships) { |
| // find first non-matches declare relationship |
| for (IRelationship rel : relationships) { |
| if (!rel.getName().equals(AsmRelationshipProvider.MATCHES_DECLARE)) { |
| return getMarkerLabel(rel); |
| } |
| } |
| return "<none>"; |
| } |
| |
| /** |
| * Get a label for the given relationship |
| * |
| * @param relationship |
| * @return |
| */ |
| private String getMarkerLabel(IRelationship relationship) { |
| IProgramElement target = model.getProgramElement( |
| (String) relationship.getTargets().get(0)); |
| return relationship.getName() |
| + " " //$NON-NLS-1$ |
| + (target != null ? target.toLinkLabelString(false) : "null") |
| + (relationship.hasRuntimeTest() ? " " + //$NON-NLS-1$ |
| UIMessages.AspectJEditor_runtimetest |
| : ""); //$NON-NLS-1$ |
| } |
| |
| /** |
| * check if this relationship comes from an aspect that has a custom marker |
| * @see AJMarkersDialog |
| */ |
| private String getCustomMarker(IRelationship relationship) { |
| // get the element in the aspect, it is source or target depending |
| // on the kind of relationship |
| List<IJavaElement> aspectEntities = new ArrayList<IJavaElement>(); |
| if (relationship.isAffects()) { |
| aspectEntities.add(model.programElementToJavaElement(relationship.getSourceHandle())); |
| } else { |
| // all targets are from the same |
| for (String target : relationship.getTargets()) { |
| aspectEntities.add(model.programElementToJavaElement(target)); |
| } |
| } |
| |
| for (IJavaElement elt : aspectEntities) { |
| if (elt != null) { // will be null if the referent is not found. Should only be in error cases |
| IType typeElement = (IType) elt.getAncestor(IJavaElement.TYPE); |
| if (typeElement != null) { |
| String customImage = AspectJPreferences.getSavedIcon(typeElement.getJavaProject() |
| .getProject(), AJMarkersDialog |
| .getFullyQualifiedAspectName(typeElement)); |
| if (customImage != null) { |
| return customImage; |
| } |
| } |
| } |
| } |
| return null; |
| } |
| |
| |
| /** |
| * Two or more markers on the same line - get the most approriate marker |
| * type to display |
| * |
| * @param firstMarkerType |
| * @param secondMarkerType |
| * @param runtimeTest |
| * @return |
| */ |
| private String getCombinedMarkerType(String firstMarkerType, |
| String secondMarkerType, boolean runtimeTest) { |
| |
| if (firstMarkerType.indexOf("source") != -1 && secondMarkerType.indexOf("source") != -1) { //$NON-NLS-1$ //$NON-NLS-2$ |
| // around advice trumps before and after |
| if (firstMarkerType.indexOf("around") != -1 || secondMarkerType.indexOf("around") != -1) { //$NON-NLS-1$ //$NON-NLS-2$ |
| return runtimeTest ? IAJModelMarker.SOURCE_DYNAMIC_AROUND_ADVICE_MARKER |
| : IAJModelMarker.SOURCE_AROUND_ADVICE_MARKER; |
| } else { |
| return runtimeTest ? IAJModelMarker.SOURCE_DYNAMIC_ADVICE_MARKER |
| : IAJModelMarker.SOURCE_ADVICE_MARKER; |
| } |
| } else if (firstMarkerType.indexOf("source") != -1 || secondMarkerType.indexOf("source") != -1) { //$NON-NLS-1$ //$NON-NLS-2$ |
| // being source and target trumps around, before, and after |
| return runtimeTest ? IAJModelMarker.DYNAMIC_SOURCE_AND_TARGET_MARKER |
| : IAJModelMarker.SOURCE_AND_TARGET_MARKER; |
| } else { |
| // around advice trumps before and after |
| if (firstMarkerType.indexOf("around") != -1 || secondMarkerType.indexOf("around") != -1) { //$NON-NLS-1$ //$NON-NLS-2$ |
| return runtimeTest ? IAJModelMarker.DYNAMIC_AROUND_ADVICE_MARKER |
| : IAJModelMarker.AROUND_ADVICE_MARKER; |
| } else { |
| return runtimeTest ? IAJModelMarker.DYNAMIC_ADVICE_MARKER |
| : IAJModelMarker.ADVICE_MARKER; |
| } |
| } |
| } |
| } |